带有 const ref 参数的自赋值行为
Behavior of self-assignment with const ref parameter
我偶然发现了一些非常古老的代码,它有一个 class 和一个定义的复制赋值运算符,它将其参数作为常量引用,但也不检查自赋值,所以本质上:
struct A
{
int q;
A(): q(3) {}
A& operator=(const A& a)
{
q = a.q;
return *this;
}
};
当 A
的实例被赋值给自身时,这个赋值运算符的行为是什么?我认为这会导致问题,因为它 "breaks" 参数的常量性,任何编译器都可以假设参数未更改并基于此进行优化。
然而,clang 和 gcc 都没有发出警告,程序运行正常。如果我在赋值运算符中赋值之前将 q
的值显式更改为 4,这也有效。
将对象绑定到 const 引用不会使其突然变为 const。那里的const
只是表示函数不能通过a
修改参数。这并不意味着所引用的对象必须是 const 本身。
因为 *this
和 a
可以合法地为同一个对象起别名,所以这样的代码没有风险。编译器不能对别名做出大胆的假设。
Self-assignment 仅当赋值运算符未 运行 完成或释放资源然后尝试从 [=20 复制时对象状态可能以某种方式损坏时才成为问题=].您的示例没有发生这种情况的风险。但是,总的来说,应该注意可能抛出的异常和资源的所有权。
我偶然发现了一些非常古老的代码,它有一个 class 和一个定义的复制赋值运算符,它将其参数作为常量引用,但也不检查自赋值,所以本质上:
struct A
{
int q;
A(): q(3) {}
A& operator=(const A& a)
{
q = a.q;
return *this;
}
};
当 A
的实例被赋值给自身时,这个赋值运算符的行为是什么?我认为这会导致问题,因为它 "breaks" 参数的常量性,任何编译器都可以假设参数未更改并基于此进行优化。
然而,clang 和 gcc 都没有发出警告,程序运行正常。如果我在赋值运算符中赋值之前将 q
的值显式更改为 4,这也有效。
将对象绑定到 const 引用不会使其突然变为 const。那里的const
只是表示函数不能通过a
修改参数。这并不意味着所引用的对象必须是 const 本身。
因为 *this
和 a
可以合法地为同一个对象起别名,所以这样的代码没有风险。编译器不能对别名做出大胆的假设。
Self-assignment 仅当赋值运算符未 运行 完成或释放资源然后尝试从 [=20 复制时对象状态可能以某种方式损坏时才成为问题=].您的示例没有发生这种情况的风险。但是,总的来说,应该注意可能抛出的异常和资源的所有权。