C++法则8:对于有引用成员的类,合成拷贝赋值运算符被定义为删除的。
C++法则8:对于有引用成员的类,合成拷贝赋值运算符被定义为删除的。
在 C++ 中,Rule of 8(法则 8)并不是一个官方术语,但通常指与特殊成员函数(如拷贝构造函数、拷贝赋值运算符、移动构造函数、移动赋值运算符等)相关的规则。这里提到的规则实际上是关于类中包含引用成员时,拷贝赋值运算符的行为。
法则 8 的解释
如果一个类包含引用成员,那么编译器会自动将合成的拷贝赋值运算符(
operator=
)定义为delete
d(删除的)。
为什么?
-
引用(
T&
)一旦初始化后就不能再绑定到另一个对象。因此,默认的拷贝赋值运算符(尝试逐个成员赋值)无法正确修改引用成员所引用的目标。 -
如果允许默认的拷贝赋值,可能会导致意外的行为或违反引用的语义。
示例
#include <iostream>class RefHolder {
public:int& ref; // 引用成员RefHolder(int& x) : ref(x) {}// 编译器不会生成默认的拷贝赋值运算符(它会被定义为 deleted)
};int main() {int a = 10, b = 20;RefHolder obj1(a);RefHolder obj2(b);// obj1 = obj2; // 错误!拷贝赋值运算符是 deleted 的return 0;
}
-
如果你尝试
obj1 = obj2;
,编译器会报错,因为RefHolder
的拷贝赋值运算符是delete
d 的。
如何解决?
如果类包含引用成员,并且你确实需要支持拷贝赋值,必须手动定义拷贝赋值运算符:
class RefHolder {
public:int& ref;RefHolder(int& x) : ref(x) {}// 手动定义拷贝赋值运算符RefHolder& operator=(const RefHolder& other) {ref = other.ref; // 注意:这里修改的是引用指向的值,而非引用本身return *this;}
};
-
但要注意,这样并不会改变
ref
引用的对象,而是修改ref
指向的值。
总结
-
如果类有引用成员,合成的拷贝赋值运算符会被
delete
d。 -
如果需要拷贝赋值,必须手动定义。
-
引用成员在赋值时不会改变绑定,只能修改被引用的值。
这个规则是 C++ 对象模型的一部分,确保引用语义的正确性。