为什么 GCC 拒绝复制赋值操作中的常量引用
Why GCC refuses a const reference within a copy-assignment operation?
我想正常重载一个常见的复制赋值运算符。起初,我使用了一个只需要对源代码的 const 引用的接口,并显式禁用接受可修改引用的接口,但我无法通过编译。编译器报告"错误:使用已删除的函数'ClassA&ClassA::operator=(ClassA&(">
当然,如果我不明显删除接口,我可以编译,但这不是我的目的。我想明确删除它,以避免意外使用它。
为什么复制赋值操作需要对源的可修改引用,而不是常量引用?赋值操作只需要只读访问源!
关于复制构造函数有一个相同的问题,为了简化,我省略了它。
我的代码有什么问题?或者我们不能删除它?
我的示例代码如下:
class ClassA {
public:
ClassA() = default;
ClassA( ClassA & ) = default;
ClassA & operator=( ClassA & )
= delete // Must comment-out this, or we can't pass the compilation.
// { cout << "ClassA & operator=( ClassA & ) executed." << endl; return *this; }
;
ClassA & operator=( ClassA && ) {
cout << "ClassA & operator=( ClassA && ) executed." << endl;
return *this;
};
ClassA & operator=( const ClassA & ) {
cout << "ClassA & operator=( const ClassA & ) executed." << endl;
return *this;
};
ClassA & operator=( const ClassA && ) {
cout << "ClassA & operator=( const ClassA && ) executed." << endl;
return *this;
};
};
int main() {
ClassA oa, ob;
ob = oa;
return EXIT_SUCCESS;
};
或者我们不能删除它?
你只是不需要这样做。如果提供用户定义的复制赋值运算符,则不会隐式声明其他运算符,即仅存在用户定义的运算符。
如果这样做,则显式标记为delete
的复制赋值运算符将参与重载解析;选择该运算符后,编译将失败。对于ob = oa;
,operator=( ClassA & )
是更好的匹配,如果不存在,operator=( const ClassA & )
将被使用并正常工作。
所以在这种情况下,你可以做
class ClassA {
public:
ClassA & operator=( ClassA && ) {
cout << "ClassA & operator=( ClassA && ) executed." << endl;
return *this;
}
ClassA & operator=( const ClassA & ) {
cout << "ClassA & operator=( const ClassA & ) executed." << endl;
return *this;
}
};
当然,如果我不明显删除接口,我可以编译,但这不是我的目的。我想明确删除它,以避免意外使用它。
你不能意外地使用不存在的东西。如果你的类定义了ClassA & operator=( const ClassA & )
,那么ClassA & operator=( ClassA & )
根本不存在(编译器不会生成它(。没有理由提供和删除它。
如果您明确删除它,然后调用:
ob = oa;
// The same as
ob.operator=(oa);
当然ClassA & operator=( ClassA & )
是最好的匹配,因为oa
是一个非常量左值。由于它被删除,这将是一个错误。
如果根本没有声明,ClassA & operator=( const ClassA & )
现在成为最佳匹配项。因此,它永远不会尝试使用ClassA & operator=( ClassA & )
因为它不存在。
如果你真的想,你仍然可以有ClassA & operator=( ClassA & ) = delete;
,并且你必须手动从 const 引用分配:
ob = static_cast<const ClassA&>(oa);
// Will now select `ClassA & operator=( const ClassA & )`
这表明您不需要非常量左值赋值运算符。但是真的没有意义,因为如果不声明ClassA & operator=( ClassA & )
无论如何它都会被用作常量引用。
- 什么时候在C++中返回常量引用是个好主意
- 通过常量引用传递参数的矩阵模板类
- 在C++中使用非常量引用作为常量
- 具有常量引用参数的函数模板专用化
- 多个"常量引用"变量可以共享同一个内存吗?
- 为什么 STL 容器适配器堆栈中的 top 返回常量引用?
- 为什么常量方法可以采用非常量引用?
- 为什么当我们有常量引用时创建临时对象?
- 如何返回向量的常量引用?
- C++:常量引用参数
- 不同于按值传递和常量引用传递的程序集
- 为什么const_cast和static_cast常量引用没有效果?
- C++ 获取函数在常量引用中按值返回的结果
- 从 BubbleSort* 类型的右值初始化 'AssortedSorter&' 类型的非常量引用无效"
- C++ 在类中使用常量引用文本时 O2 内存泄漏
- 是否可以跨 dll 边界返回常量引用/指向 std::vectors?
- C++中大多数/所有 setter 函数的参数是否应该写为常量引用?
- 通过非常量引用参数修改常量引用参数
- 将常量引用传递给线程
- 为什么C++中没有常量引用,就像常量指针一样?