简体   繁体   English

Accelerated C ++ 14-5:自定义字符串类和引用计数器适用于一个构造函数,但不适用于另一个构造函数

[英]Accelerated C++ 14-5: Custom string class and reference counter works for one constructor but not another

For those of you familiar with the book Accelerated C++, I was writing a solution to problem 14-5 and came across some interesting behavior that I can't explain. 对于那些熟悉Accelerated C ++一书的人,我正在编写问题14-5的解决方案,并遇到了一些我无法解释的有趣行为。

The problem involves using custom string and pointer/reference counter classes to implement a program that can concatenate vectors of strings and create pictures out of them. 问题涉及使用自定义字符串和指针/引用计数器类来实现一个程序,该程序可以连接字符串的向量并从中创建图片。

Essentially, the part of the program in question is the following: 从本质上讲,该程序的部分内容如下:

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

}

It seems as though my reference counter isn't working properly when I use the commented line: the result I get is as if every str in test were the empty string. 当我使用注释行时,似乎我的引用计数器工作不正常:我得到的结果就好像test中的每个str都是空字符串一样。

Here are my implementations of getline and the relevant parts of the str and ptr classes: 以下是我的getline实现以及strptr类的相关部分:

str class: 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 class: 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;
    }
}

The vec class is essentially a subset of std::vector . vec类本质上是std::vector的子集。 I can supply those details here too, if necessary. 如有必要,我也可以在这里提供这些细节。

And here is getline: 这是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;
}

Even though you are counting references correctly, you are still sharing the same pointer between the instances. 即使您正确计算引用,您仍然在实例之间共享相同的指针。 So getline is modifying the same str object. 所以getline正在修改同一个str对象。 You need to implement Copy-on-write in str . 您需要在str实现Copy-on-write

Here is what's wrong: 这是错的:

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;
}

So, you should do: 所以,你应该这样做:

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

instead of clearing the shared instance. 而不是清除共享实例。

When you call: 你打电话时:

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

now s and a copy of s in test share the same data. 现在stests副本共享相同的数据。 During the next iteration of the while loop getline function calls s.data->clear() , which clears data in both s and the copy of s in test . 在的下一次迭代while循环getline函数调用s.data->clear()它清除在两个数据s和副本stest

When you call: 你打电话时:

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

the str(s.begin(),s.end()) constructor creates a temp str object with a copy of the data that was in s and pushes that object into test . str(s.begin(),s.end())构造函数创建一个临时str对象,其中包含s中的数据副本,并将该对象推送到test So now the temp object and the copy in test share the same data, which is a non-shared copy of s . 所以现在临时对象和test的副本共享相同的数据,这是s的非共享副本。 The temp object gets destroyed and the copy in test stays intact. 临时对象被破坏, test的副本保持不变。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 将一个 class 作为输入传递给另一个 class,该 class 为其构造函数 C++ 采用多个参考接口 - passing One class as input to another class that takes multiple reference interfaces for his constructor C++ 将两个char *带入另一个std :: string的字符串构造函数在c ++ 14中工作,但不是c ++ 17 - string constructor taking two char* into another std::string works in c++14 but not c++17 是否可以在C ++中的另一个类的构造函数中声明一个类的对象? - Is it possible to declare an object of one class in the constructor of another class in C++? 在另一个C ++类的构造函数中实例化一个类的对象? - Instantiate an object of one class in the constructor of another class C++? Class 下面定义的另一个 Class 内部的指针引用? (C++ 14,VS 2019) - Class Pointer reference inside of another Class defined below? (C++ 14, VS 2019) 类中的c ++引用字段抛出构造函数 - c++ reference field in a class throw the constructor c ++ undefined引用类构造函数 - c++ undefined reference class constructor 发送参考qplaintextedit到C ++构造函数类 - send reference qplaintextedit to C++ constructor class 类构造函数如何在C ++中工作 - How class constructor works in C++ 基类构造函数中的C ++参考 - C++ reference in base class constructor
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM