为什么 GCC 拒绝复制赋值操作中的 const 引用?
Why GCC refuses a const reference within a copy-assignment operation?
我想正常重载一个普通的复制赋值运算符。
起初我使用了一个只需要对源代码进行常量引用的接口,
并明确禁用接受可修改引用的接口,
但我无法通过编译。
编译器报告 "error: use of deleted function ‘ClassA& ClassA::operator=(ClassA&)"
当然,如果我不显式删除接口,我可以编译,但这不是我的目的。
我想明确删除它,以避免意外使用它。
为什么复制赋值操作需要对源的可修改引用,而不是 const 引用?
赋值操作只需要以只读方式访问源!
关于复制构造函数也有同样的问题,为了简化我省略了。
我的代码有什么问题?或者我们不能删除它?
我的示例代码如下:
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;
};
or we can NOT delete it?
你只是不需要那样做。如果您提供 user-defined 复制赋值运算符,则不会有其他运算符 implicitly-declared,即只有 user-defined 会存在。
如果这样做,您明确标记为 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;
}
};
Of course, I can get compiled if I don't expicitly delete the interface, but that is not my purpose. I'd like to expicitly delete it, to avoid unexpected using it.
你不能意外地使用不存在的东西。如果您的 class 定义了 ClassA & operator=( const ClassA & )
,那么 ClassA & operator=( ClassA & )
将根本不存在(编译器不会生成)。没有理由提供&删除它。
如果您明确删除它,然后调用:
ob = oa;
// The same as
ob.operator=(oa);
当然 ClassA & operator=( ClassA & )
是最佳匹配,因为 oa
是 non-const 左值。既然删了,就报错
如果根本不声明,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 & )`
这表明您不需要 non-const 左值赋值运算符。但这真的没有意义,因为如果未声明 [=12=],它将被用作 const 引用。
我想正常重载一个普通的复制赋值运算符。 起初我使用了一个只需要对源代码进行常量引用的接口, 并明确禁用接受可修改引用的接口, 但我无法通过编译。 编译器报告 "error: use of deleted function ‘ClassA& ClassA::operator=(ClassA&)"
当然,如果我不显式删除接口,我可以编译,但这不是我的目的。 我想明确删除它,以避免意外使用它。
为什么复制赋值操作需要对源的可修改引用,而不是 const 引用? 赋值操作只需要以只读方式访问源!
关于复制构造函数也有同样的问题,为了简化我省略了。
我的代码有什么问题?或者我们不能删除它?
我的示例代码如下:
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;
};
or we can NOT delete it?
你只是不需要那样做。如果您提供 user-defined 复制赋值运算符,则不会有其他运算符 implicitly-declared,即只有 user-defined 会存在。
如果这样做,您明确标记为 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;
}
};
Of course, I can get compiled if I don't expicitly delete the interface, but that is not my purpose. I'd like to expicitly delete it, to avoid unexpected using it.
你不能意外地使用不存在的东西。如果您的 class 定义了 ClassA & operator=( const ClassA & )
,那么 ClassA & operator=( ClassA & )
将根本不存在(编译器不会生成)。没有理由提供&删除它。
如果您明确删除它,然后调用:
ob = oa;
// The same as
ob.operator=(oa);
当然 ClassA & operator=( ClassA & )
是最佳匹配,因为 oa
是 non-const 左值。既然删了,就报错
如果根本不声明,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 & )`
这表明您不需要 non-const 左值赋值运算符。但这真的没有意义,因为如果未声明 [=12=],它将被用作 const 引用。