不在复制赋值运算符中检查一个对象是否被赋值给它自己真的安全吗?
Is it really safe not to check in the copy assignemt operator whether an object is assigned to itself?
这是我发现的实现 "Rule of Three" 的示例:
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;
}
如您所见,复制赋值运算符中的检查已被删除,因为创建局部变量然后删除成员指针并将其分配给局部变量。但如果我写:
int main() {
int vals[ 4 ] = { 11, 22, 33, 44 };
Array a1( 4, vals );
a1 = a1; // here I assigned a1 to itself
return 0;
}
我将 a1
分配给了它自己,这是否意味着 a1
的 vals
被删除,然后在复制赋值运算符中分配了本地的 a
?这是正确的方法吗?我的代码有缺陷吗?
- 非常感谢任何提示和建议。
复制赋值运算符将起作用,因为自赋值将具有预期的行为:数组的值内容将保持不变。
你不做测试的损失是,如果你已经拥有一个数组,你将分配一个你不需要的数组,执行你不必做的复制,然后销毁一些东西你本可以保留。
这对性能是否重要...这在很大程度上取决于使用相关因素。毕竟,如果您执行自我复制,这只是一个问题。你多久做一次?如果你真的不经常(或从来没有)这样做,那么测试只是一个你不需要的条件分支。
同时考虑vector
的定义。当 iterators/pointers/references 变为 vector
失效时,它有非常具体的情况。而复制 vector
是 不是其中之一 。因此,如果对象存储的位置是数组类型接口的一部分(vector
的方式),那么进行自我复制对您的接口具有更广泛的影响。
这是我发现的实现 "Rule of Three" 的示例:
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;
}
如您所见,复制赋值运算符中的检查已被删除,因为创建局部变量然后删除成员指针并将其分配给局部变量。但如果我写:
int main() {
int vals[ 4 ] = { 11, 22, 33, 44 };
Array a1( 4, vals );
a1 = a1; // here I assigned a1 to itself
return 0;
}
我将 a1
分配给了它自己,这是否意味着 a1
的 vals
被删除,然后在复制赋值运算符中分配了本地的 a
?这是正确的方法吗?我的代码有缺陷吗?
- 非常感谢任何提示和建议。
复制赋值运算符将起作用,因为自赋值将具有预期的行为:数组的值内容将保持不变。
你不做测试的损失是,如果你已经拥有一个数组,你将分配一个你不需要的数组,执行你不必做的复制,然后销毁一些东西你本可以保留。
这对性能是否重要...这在很大程度上取决于使用相关因素。毕竟,如果您执行自我复制,这只是一个问题。你多久做一次?如果你真的不经常(或从来没有)这样做,那么测试只是一个你不需要的条件分支。
同时考虑vector
的定义。当 iterators/pointers/references 变为 vector
失效时,它有非常具体的情况。而复制 vector
是 不是其中之一 。因此,如果对象存储的位置是数组类型接口的一部分(vector
的方式),那么进行自我复制对您的接口具有更广泛的影响。