如何避免重载赋值运算符将右值转换为左值
How to avoid overloaded assignment operator turning rvalue to lvalue?
据我所知,返回*this
是编写重载operator=
的规范。但这可能会将右值提升为左值!
struct Foo {
Foo& operator=(const Foo &t) { return *this; }
};
int main() {
const Foo &ref = Foo();
//Foo &ref1 = Foo(); // This line won't compile.
//But the following line compiles. Isn't it dangerous?
//Also please note that if = is not overloaded, the synthesized operator= will NOT let it compile.
Foo &ref2 = (Foo() = Foo());
return 0;
}
你说得对。简单的回答是,这是合法的,但由于你指出的原因,这是危险的。
另一个(类似的)例子被添加到C++11中,作为标准的一部分,带有右值流输出,返回一个左值引用。
template <class charT, class traits, class T>
basic_ostream<charT, traits>&
operator<<(basic_ostream<charT, traits>&& os, const T& x);
因此std::ostream& s = std::ofstream("foo.txt") << "Oh boy";
是合法的,但它创建了一个悬空引用。
我相信,C++11编译器将允许成员函数被限制在对象为左值的情况下,这应该可以让你完全避免这个问题。以下仅允许在*this
为左值时进行赋值,因此可以防止意外转换。
struct Foo {
Foo& operator=(const Foo &t) & { return *this; }
};
正如第一个答案所指出的,您所做的是合法的,但会导致悬空引用。您可以在不重载赋值运算符的情况下获得大致相同的结果:
#include <iostream>
struct Foo {
Foo(int arg) : val(arg) { std::cout << "ctor " << val << "n"; }
~Foo() { std::cout << "dtor " << val << "n"; }
int val;
};
int main() {
Foo &ref = (Foo(1) = Foo(2));
std::cout << "undefined behavior: " << ref.val << "n";
return 0;
}
产生以下输出:
ctor 1
ctor 2
dtor 2
dtor 2
未定义行为:2
如您所见,先构造Foo(1)
的临时,然后构造Foo(2)
的临时。然而,在我们可以对引用执行任何操作之前,这两个对象都已被销毁,因此后面的行将导致未定义的行为。
相关文章:
- 是否应避免从非常量迭代器转换为常量迭代器?
- 使用算术运算符时如何避免从 char 到 int 的隐式转换
- 如何避免强制转换运算符 () 和访问运算符 [] 冲突?
- 避免从单一元素向量转换为基元类型
- 是否应该避免这种从 int 到双精度的静态转换?
- 静态强制转换以避免 IDE 警告?
- 移植到 64 位时如何避免size_t int 强制转换警告?
- 如何在预处理器 (#if) 中强制转换静态 const 以避免溢出
- 如何避免字符串到整数转换情况下的无效参数异常
- 如何将 std::array<double, 100> 转换为 std::array<float, 100> ?(避免明显的样板实现)
- 避免将 Int 转换为双重类型转换舍入
- 将一组类转换为类模板并避免构造函数模棱两可
- 避免对模板运算符过载的隐式参数转换
- 如何避免空字符转换为 0?
- 两种类型转换有何不同?
- 如何避免使用模板类型的派生类进行多态性动态强制转换
- C++ 设计模式,以避免复制和向下转换
- 如何避免隐式转换类型
- 高效的无符号到签名转换,避免实现定义的行为
- 从 C 转换为 C++避免<strsafe.h>