Mar*_*arc 13 c++ constructor copy-constructor assignment-operator c++11
考虑一类需要复制的副本.副本中的绝大多数数据元素必须严格反映原始数据元素,但是有少数元素的状态不被保留且需要重新初始化.
从复制构造函数调用默认赋值运算符是不好的形式?
默认赋值运算符对于Plain Old Data(int,double,char,short)以及每个赋值运算符的用户定义类都表现良好.指针需要单独处理.
一个缺点是该方法使得赋值运算符瘫痪,因为不执行额外的重新初始化.也无法禁用赋值运算符的使用,从而通过使用不完整的默认赋值运算符打开用户创建损坏类的选项A obj1,obj2; obj2=obj1; /* Could result is an incorrectly initialized obj2 */.
a(orig.a),b(orig.b)...除了a(0),b(0) ...必须写之外,放宽要求是很好的.需要写入所有初始化两次会产生两个错误位置,如果double x,y,z要将新变量(例如)添加到类中,初始化代码需要在至少2个位置而不是1个位置正确添加.
有没有更好的办法?
在C++ 0x中有更好的方法吗?
class A {
public:
A(): a(0),b(0),c(0),d(0)
A(const A & orig){
*this = orig; /* <----- is this "bad"? */
c = int();
}
public:
int a,b,c,d;
};
A X;
X.a = 123;
X.b = 456;
X.c = 789;
X.d = 987;
A Y(X);
printf("X: %d %d %d %d\n",X.a,X.b,X.c,X.d);
printf("Y: %d %d %d %d\n",Y.a,Y.b,Y.c,Y.d);
Run Code Online (Sandbox Code Playgroud)
输出:
X: 123 456 789 987
Y: 123 456 0 987
Run Code Online (Sandbox Code Playgroud)
备用复制构造函数:
A(const A & orig):a(orig.a),b(orig.b),c(0),d(orig.d){} /* <-- is this "better"? */
Run Code Online (Sandbox Code Playgroud)
Jef*_*rdy 14
正如布朗指出的那样,你最好在复制结构方面实施任务.我更喜欢他的替代习语:
T& T::operator=(T t) {
swap(*this, t);
return *this;
}
Run Code Online (Sandbox Code Playgroud)
它有点短,可以利用一些深奥的语言功能来提高性能.像任何好的C++代码一样,它也有一些细微之处需要注意.
首先,t有意地通过值传递参数,这样就可以调用复制构造函数(大部分时间),我们可以在不影响原始值的情况下修改我们内心的内容.使用const T&将无法编译,并将T&通过修改assign-from值触发一些令人惊讶的行为.
这种技术还需要swap以不使用类型赋值运算符的方式专门用于类型(如同std::swap),否则将导致无限递归.小心任何杂散的using std::swap或using namespace std,因为他们将拉std::swap入的范围和造成的问题,如果你不擅长swap的T.如果已定义,则过载分辨率和ADL将确保使用正确的交换版本.
有几种方法可以swap为类型定义.第一种方法使用swap成员函数来完成实际工作,并具有swap委托给它的特化,如下所示:
class T {
public:
// ....
void swap(T&) { ... }
};
void swap(T& a, T& b) { a.swap(b); }
Run Code Online (Sandbox Code Playgroud)
这在标准库中很常见; std::vector例如,以这种方式实现交换.如果你有一个swap成员函数,你可以直接从赋值运算符调用它,并避免函数查找的任何问题.
另一种方法是声明swap为友元函数并让它完成所有工作:
class T {
// ....
friend void swap(T& a, T& b);
};
void swap(T& a, T& b) { ... }
Run Code Online (Sandbox Code Playgroud)
我更喜欢第二个,因为swap()通常不是类接口的组成部分; 它似乎更适合作为自由功能.然而,这是一个品味问题.
swap对类型进行优化是实现C++ 0x中右值引用的一些好处的常用方法,因此如果类可以利用它并且您确实需要性能,那么通常这是一个好主意.
使用您的复制构造函数版本,首先默认构造成员,然后分配成员。
对于整型,这并不重要,但如果您有像 s 这样的重要成员,那么std::string这是不必要的开销。
因此,是的,一般来说,您的替代复制构造函数更好,但如果您只有整型类型作为成员,那么这并不重要。