简体   繁体   English

复制构造函数可以采用非const参数吗?

[英]Can a copy-constructor take a non-const parameter?

I have this problem, there is a function foo() as follows, 我有这个问题,有一个函数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
}

And AFAIK, vec will invoke ClassA 's copy-ctor to make a copy of the newly created object a , and here is the problem. 而AFAIK, vec将调用ClassA的copy-ctor来复制新创建的对象a ,这就是问题所在。 If I define ClassA 's copy-ctor the usual way, 如果我用通常的方式定义ClassA的copy-ctor,

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

then object a and its copy (created by vec) will have pointers _ptr pointing to the same area, when foo finishes, a will call the destructor to release _ptr , then a 's copy in vec will be a dangling pointer, right? 那么物体a及复印件(由VEC创建)指针_ptr指向同一个区域,当foo结束, a将调用析构函数释放_ptr ,然后a中的副本vec将是一个悬摆指针,对不对? Due to this problem, I want to implement ClassA 's copy-ctor this way, 由于这个问题,我想以这种方式实现ClassA的copy-ctor,

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

Is my implementation ok? 我的实施是否正常? Or any other way can help accomplish the job? 或者任何其他方式可以帮助完成这项工作?

To answer your titular question: Yes, any constructor for a class T that has one mandatory argument of type T & or T const & (it may also have further, defaulted arguments) is a copy constructor. 回答你的名义问题:是的,类T任何构造T const &都有一个复制构造T const &它有一个类型为T &T const &强制参数T const & (它可能还有其他的默认参数)。 In C++11, there's also a move constructor which requires one argument of type T && . 在C ++ 11中,还有一个移动构造函数,它需要一个类型为T &&参数。

Having a non-constant copy constructor that actually mutates the argument gives your class very unusual semantics (usually "transfer semantics") and should be extensively documented; 拥有一个实际改变参数的非常量复制构造函数会给你的类带来非常不寻常的语义(通常是“传递语义”)并且应该被广泛记录; it also prevents you from copying something constant (obviously). 它还可以防止你复制一些不变的东西(显然)。 The old std::auto_ptr<T> does exactly that. 旧的std::auto_ptr<T>正是如此。

If at all possible, the new C++11-style mutable rvalue references and move constructors provide a far better solution for the problem of "moving" resources around when they're no longer needed in the original object. 如果可能的话,新的C ++ 11样式的可变rvalue引用和移动构造函数为原始对象中不再需要的“移动”资源的问题提供了更好的解决方案。 This is because an rvalue reference is a reference to a mutable object, but it can only bind to "safe" expressions such as temporaries or things that you have explicitly cast (via std::move ) and thus marked as disposable. 这是因为rvalue引用是对可变对象的引用,但它只能绑定到“安全”表达式,例如临时或显式转换的事物(通过std::move ),因此标记为一次性。

C++11 introduced move constructors for this exact purpose: C ++ 11为此目的引入了移动构造函数:

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

Alternatively you can declare _ptr to be a shared pointer: 或者,您可以将_ptr声明为共享指针:

std::shared_ptr<char[]> _ptr;

and then default denerated copy constructor will do just fine. 然后默认的denerated copy构造函数就可以了。

You should not copy the pointer, you should copy the context that the pointer is pointing to. 您不应该复制指针,您应该复制指针指向的上下文。 You should also initialize the class by telling it how many elements you want, instead of allocating it by accessing a public pointer. 您还应该通过告诉它需要多少元素来初始化类,而不是通过访问公共指针来分配它。

Since you want to copy the object, not move it, you should allocate resources in the new object when copying. 由于您要复制对象而不是移动它,因此您应该在复制时在新对象中分配资源。

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

However, if you know that the object you will copy isn't used after it's copied, you could move it's resources instead. 但是,如果您知道要复制的对象在复制后未使用,则可以移动它的资源。

The problem with your implementation is that you will not be able to pass temporary objects as arguments for this copy-ctor (temporaries are always const ). 您的实现的问题是您将无法将临时对象作为此copy-ctor的参数传递(临时对象始终为const )。 Like already mentioned the best solution would be to move to c++11 and use move semantics. 就像已经提到的那样,最好的解决方案是转移到c ++ 11并使用移动语义。 If it is not possible shared_array can be an alternative. 如果不可能, shared_array可以替代。

Additional comment: 附加评论:

Avoid these kind of problems creating the object with new and storing pointers to the object in the vector. 避免使用new创建对象并在向量中存储指向对象的指针时出现这些问题。

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

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM