为什么允许T()= T()?

Rim*_*imo 18 c++ language-design operator-overloading rvalue temporary-objects

我相信表达式T()创建了一个rvalue(由标准).但是,以下代码编译(至少在gcc4.0上):

class T {};

int main()
{
    T() = T();
}
Run Code Online (Sandbox Code Playgroud)

我在技术上知道这是可能的,因为成员函数可以在temporaries上调用,而上面只是调用operator =在从第一个创建的rvalue临时T().

但从概念上讲,这就像为rvalue分配一个新值.是否允许这样做有充分的理由吗?

编辑:我发现这个奇怪的原因是它在内置类型上被严格禁止,但允许在用户定义的类型上使用.例如,int(2) = int(3)不会编译,因为这是"赋值中的无效左值".

所以我想真正的问题是,这种有点不一致的行为是否构成了语言的原因?还是出于某种历史原因?(例如,在rvalue表达式上只允许调用const成员函数在概念上会更健全,但是这可能无法完成,因为这可能会破坏一些现有代码.)

Inv*_*rse 13

这纯粹是因为操作符超载,以及你可能会超载operator =以执行更奇特的操作,例如打印到控制台,或锁定互斥锁,或任何其他东西.

  • 而且不仅仅是operator =,还有构造函数.C++中有很多奇怪的结构,编译器只是耸耸肩,希望你知道你在做什么.:-) (17认同)

AnT*_*AnT 7

是的,您要为右值分配新值.更确切地说,您operator =在rvalue上调用成员函数.由于您没有使用内置赋值运算符,为什么您认为这应该是一个问题?operator =是类的成员函数,在大多数方面类似于类的任何其他成员函数,包括它可以在rvalues上调用的事实.

您还应该考虑这样一个事实,即"作为右值"是表达式的属性,而不是对象的属性.这是事实,T()表达式计算结果为右值.然而,T()表达式产生的临时对象仍然是一个对象,也可以作为左值进行访问.例如,可以在赋值结果上调用其他一些成员函数,它将通过*this左值看到临时对象的"新"(新分配)值

(T() = T()).some_member_function();
Run Code Online (Sandbox Code Playgroud)

您还可以通过将const引用附加到它来延长临时的生命周期,并且通过const T& r = T() = T();的值r将是对象的"新"值. 正如约翰内斯在评论中正确指出的那样,这不会将其附加到临时性的.

  • @Rhimo:这会破坏合理的结构,比如`Atomic(std :: cout)<< 1 <<"uninterrupted output"<< std :: endl;` (3认同)
  • 这里的小疏忽,我认为:`const T&r = T()= T();`不起作用.您正在尝试将const引用绑定到左值(由副本赋值运算符返回的`T&`),然后临时将被销毁.如果您尝试将其绑定到引用临时值的右值,则仅延长生命周期. (3认同)

fre*_*low 5

您可以限制operator =仅适用于C++ 0x中的左值:

class T
{
public:
    T& operator=(const T&) & = default;
};
Run Code Online (Sandbox Code Playgroud)


Joh*_*itb 4

这就是为什么可以实现标准库中的几个类。例如考虑std::bitset<>::operator[]

\n\n
// bit reference:\nclass reference {\n  friend class bitset;\n  reference();\npublic:\n  \xcb\x9creference();\n  reference& operator=(bool x);           // for b[i] = x;\n  reference& operator=(const reference&); // for b[i] = b[j];\n  bool operator\xcb\x9c() const; // flips the bit\n  operator bool() const;  // for x = b[i];\n  reference& flip();      // for b[i].flip();\n};\n\nreference operator[](size_t pos); // for b[i];\n
Run Code Online (Sandbox Code Playgroud)\n\n

如果这样做, bits[i] = true您就可以将某个值准确地分配给类类型的右值。返回的代理operator[]可以访问空间有效地打包成整数的位。

\n