8

我有这个问题,有一个功能foo()如下,

vector<ClassA> vec;

void foo()
{
    ClassA a;   //inside foo, a ClassA object will be created
    a._ptr = new char[10];

    vec.push_back(a);   //and this newly created ClassA object should be put into vec for later use
}

并且 AFAIKvec将调用ClassA的 copy-ctor 来制作新创建的 object 的副本,a这就是问题所在。如果我ClassA以通常的方式定义 's copy-ctor,

ClassA::ClassA(const ClassA &ra) : _ptr(0)
{
    _ptr = ra._ptr;
}

那么 objecta及其副本(由 vec 创建)将具有_ptr指向同一区域的指针,当foo完成时,a将调用析构函数来 release _ptr,然后a' 的副本vec将是一个悬空指针,对吗?由于这个问题,我想以ClassA这种方式实现 's copy-ctor,

ClassA::ClassA(ClassA &ra) : _ptr(0) //take non-const reference as parameter
{
    std::swap(_ptr, a._ptr);
}

我的实施好吗?或者任何其他方式可以帮助完成这项工作?

4

5 回答 5

9

回答您的名义问题:是的,T具有一个强制类型参数T &T const &(它还可能具有更多默认参数)的类的任何构造函数都是复制构造函数。在 C++11 中,还有一个移动构造函数,它需要一个 type 参数T &&

拥有一个实际改变参数的非常量复制构造函数会给你的类带来非常不寻常的语义(通常是“转移语义”),并且应该被广泛记录;它还可以防止您复制常量(显然)。老人std::auto_ptr<T>正是这样做的。

如果可能的话,新的 C++11 风格的可变右值引用和移动构造函数为原始对象中不再需要资源时“移动”资源的问题提供了更好的解决方案。这是因为右值引用是对可变对象的引用,但它只能绑定到“安全”表达式,例如临时对象或您已显式转换(通过std::move)并因此标记为一次性的东西。

于 2012-07-27T08:25:23.100 回答
3

C++11 为此目的引入了移动构造函数:

ClassA::ClassA(ClassA&& ra)
: _ptr(ra._ptr)
{
    ra._ptr = nullptr;
}

或者,您可以声明_ptr为共享指针:

std::shared_ptr<char[]> _ptr;

然后默认的 denerated 复制构造函数就可以了。

于 2012-07-27T08:16:49.870 回答
2

你不应该复制指针,你应该复制指针指向的上下文。您还应该通过告诉它您想要多少元素来初始化该类,而不是通过访问公共指针来分配它。

由于您要复制对象,而不是移动它,因此您应该在复制时在新对象中分配资源。

class A {

        int* p_;
        int size_;
public:

        A(int size) 
        : p_(new int[size]()), 
        size_(size) {
        }

        A(const A &a) 
        : p_(new int[a.size_]),
         size_(a.size_) {               
                std::copy(a.p_, a.p_ + a.size_, p_);
        }

        ...

};


int main () {
        A a(10);
        vec.push_back(a);
}

但是,如果您知道要复制的对象在复制后未使用,则可以移动它的资源。

于 2012-07-27T08:32:59.097 回答
1

您的实现的问题是您将无法将临时对象作为此 copy-ctor 的参数传递(临时对象始终为const)。就像已经提到的那样,最好的解决方案是迁移到 c++11 并使用移动语义。如果不可能的话shared_array可以换一个。

于 2012-07-27T08:24:47.117 回答
0

附加评论:

避免此类问题创建对象new并在向量中存储指向对象的指针。

于 2012-07-27T08:29:28.700 回答