不检查 copy assignemt 运算符是否将对象分配给自身真的安全吗?

Is it really safe not to check in the copy assignemt operator whether an object is assigned to itself?

提问人:Maestro 提问时间:12/11/2018 最后编辑:Maestro 更新时间:12/11/2018 访问量:88

问:

这是我找到的一个实现“三法则”的示例:

class Array { 
    public: 
        int size; 
        int* vals;
        Array() : size(0), vals(NULL){}
        Array( int s, int* v );
        Array(const Array&); // 1
        Array& operator=(const Array&); // 2
        ~Array(); // 3
}; 

Array::~Array() { 
   delete []vals; 
   vals = NULL; 
} 

Array::Array( int s, int* v ){
    size = s; 
    vals = new int[size]; 
    std::copy( v, v + size, vals ); 
} 

Array::Array(const Array& rhs):
    size(rhs.size),
        vals((rhs.size) ? new int[size] : NULL)
{
    if(size)
        std::copy(rhs.vals, rhs.vals + rhs.size, vals);
}

Array& Array::operator=(const Array& rhs){
//  if(this == &rhs) // no need
//      return *this;
    int* a = (rhs.size)? new int[rhs.size] : NULL; // this is why we don't need the above check: if this line throws then vals is untouched. if this is ok (local variable) then continue (next won't throw).
    std::copy(rhs.vals, rhs.vals + rhs.size, a); // copying to a even (self assignment won't harm)
    delete[] vals;
    vals = a;
    size = rhs.size;

    return *this;
}

如上所示,Copy Assignment Operator 中的检查被删除,因为事实是创建一个局部变量,然后删除成员指针并为其分配本地指针。但是,如果我写,我有什么关系:

int main() {
   int vals[ 4 ] = { 11, 22, 33, 44 };  
   Array a1( 4, vals ); 

   a1 = a1; // here I assigned a1 to itself

    return 0;
}

我分配给自己,这是否意味着 's 被删除,然后在 Copy assignment 运算符中分配本地的?这是正确的方法吗?我的代码是否存在一些缺陷?a1a1valsa

  • 任何提示,建议都非常感谢。
C++ 复制赋值 三法则

评论

2赞 NathanOliver 12/11/2018
会给你带来什么问题?您的复制分配操作员希望正确处理它,但效率不高。a1 = a1;
0赞 Maestro 12/11/2018
@NathanOliver:如何提高效率?
0赞 curiousguy 12/11/2018
大多数(可能存在“异常”)需要(为了正确性)检查的代码都不是异常安全的,并且可能需要一个 catch 子句,以便在新抛出时不会使对象处于错误状态。
0赞 Maestro 12/11/2018
@curiousguy:你的意思是我应该添加异常处理?
3赞 NathanOliver 12/11/2018
请注意,您所做的基本上是手动实现复制和交换习惯用语。如果您对自我分配的复制成本感到满意,您可能想使用它,恕我直言,它更干净。

答:

8赞 Nicol Bolas 12/11/2018 #1

复制赋值运算符将起作用,从某种意义上说,自赋值将具有预期的行为:数组的值内容将保持不变。

不做测试的损失是,如果你已经持有一个数组,你将分配一个你不需要的数组,执行一个你不必做的复制,然后销毁一些你可以保留的东西。

这是否对性能有影响......这将在很大程度上取决于使用情况相关因素。毕竟,只有在执行自复制时,这才是一个问题。你多久做一次?如果你真的不经常(或从来没有)这样做,那么测试只是一个你不需要的条件分支。

同时,考虑 的定义。它有非常具体的情况,当迭代器/指针/引用进入 无效时。复制不是其中之一。因此,如果对象存储的位置是阵列类型接口的一部分(它的方式),那么执行自复制对您的接口具有更广泛的影响。vectorvectorvectorvector

评论

0赞 Maestro 12/12/2018
谢谢你明白了。最后一个问题:那么,每当我达到“三法则”时,我是否需要使用“复制和交换”?