1

对于那些熟悉 Accelerated C++ 一书的人,我正在编写问题 14-5 的解决方案,并且遇到了一些我无法解释的有趣行为。

该问题涉及使用自定义字符串和指针/引用计数器类来实现可以连接字符串向量并从中创建图片的程序。

本质上,有问题的程序部分如下:

int main()
{
    vec<str> test;
    str s;

    while(getline(std::cin,s))
    {
            test.push_back(str(s.begin(),s.end()));
            //test.push_back(s); // This line doesn't work here - why?

            // Using the above line results in every str in test being 
            // the empty string
    }

    // Use the vec<str> to make pictures

}

当我使用注释行时,似乎我的引用计数器无法正常工作:我得到的结果好像每个strintest都是空字符串。

以下是我对和类getline的实现和相关部分:strptr

str班级:

class str
{
    friend std::istream& getline(std::istream &is, str &s);

public:
    typedef char* iterator;
    typedef const char* const_iterator;
    typedef size_t size_type;

    str() : data(new vec<char>) { }
    str(size_type n, char c) : data(new vec<char>(n,c)) { }

    str(const char *cp) : data(new vec<char>)
    {
            std::copy(cp,cp+std::strlen(cp),std::back_inserter(*data));
    }

    template <class InputIterator>
    str(InputIterator b, InputIterator e) : data(new vec<char>)
    {
            std::copy(b,e,std::back_inserter(*data));
    }

    // Other str member functions and operators
private:
    ptr< vec<char> > data;
};

ptr班级:

template <class T>
class ptr
{
public:
    void make_unique()
    {
            if(*refptr != 1)
            {
                    --*refptr;
                    refptr = new std::size_t(1);
                    p = p ? clone(p) : 0;
            }
    }

    ptr() : p(0), refptr(new std::size_t(1)) { }
    ptr(T* t) : p(t), refptr(new std::size_t(1)) { }

    ptr(const ptr &h) : p(h.p), refptr(h.refptr) { ++*refptr; }
    ptr& operator=(const ptr &);
    ~ptr();

    T& operator*() const
    {
            if(p)
            {
                    return *p;
            }

            throw std::runtime_error("unbound ptr");
    }

    T* operator->() const
    {
            if(p)
            {
                    return p;
            }

            throw std::runtime_error("unbound ptr");
    }

private:
    T* p;
    std::size_t* refptr;
};

template <class T>
ptr<T>& ptr<T>::operator=(const ptr &rhs)
{
    ++*rhs.refptr;
    // free the left hand side, destroying pointers if appropriate
    if(--*refptr == 0)
    {
            delete refptr;
            delete p;
    }

    // copy in values from the right-hand side
    refptr = rhs.refptr;
    p = rhs.p;
    return *this;
}

template <class T>
ptr<T>::~ptr()
{
    if(--*refptr == 0)
    {
            delete refptr;
            delete p;
    }
}

该类vec本质上是std::vector. 如有必要,我也可以在这里提供这些详细信息。

这是getline:

std::istream& getline(std::istream &is, str &s)
{
    s.data->clear();
    char c;
    while(is.get(c))
    {
        if(c != '\n')
        {
            s.data->push_back(c);
        }
        else
        {
            break;
        }
    }

return is;
}
4

2 回答 2

2

即使您正确地计算引用,您仍然在实例之间共享相同的指针。getline修改同一个str对象也是如此。您需要.str

这是错误的:

std::istream& getline(std::istream &is, str &s)
{
    s.data->clear();          //should make a copy of data first
    char c;
    while(is.get(c))
    {
        if(c != '\n')
        {
            s.data->push_back(c);
        }
        else
        {
            break;
        }
    }

return is;
}

所以,你应该这样做:

s.data = ptr(new vec<char>());

而不是清除共享实例。

于 2014-12-21T18:36:53.843 回答
1

你打电话时:

test.push_back(s); // This line doesn't work here - why?

now和ins的副本共享相同的数据。在循环函数调用的下一次迭代中,这会清除两者中的数据以及in的副本。stestwhilegetlines.data->clear() sstest

你打电话时:

test.push_back(str(s.begin(),s.end()));

str(s.begin(),s.end())构造函数创建一个str带有数据副本的临时对象,并将s该对象推入test. 所以现在 temp 对象和 in 中的副本test共享相同的数据,这是s. 临时对象被破坏并且副本test保持不变。

于 2014-12-21T19:28:29.837 回答