18

我相信表达式T()会创建一个右值(按标准)。但是,以下代码可以编译(至少在 gcc4.0 上):

class T {};

int main()
{
    T() = T();
}

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

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

编辑:我觉得这很奇怪的原因是它严格禁止内置类型但允许用户定义类型。例如,int(2) = int(3)不会编译,因为那是“赋值中的无效左值”。

所以我想真正的问题是,这种在语言中内置的有点不一致的行为是有原因的吗?还是出于某种历史原因?(例如,仅允许在右值表达式上调用 const 成员函数在概念上会更合理,但不能这样做,因为这可能会破坏一些现有代码。)

4

5 回答 5

13

之所以允许这样做,纯粹是因为运算符重载,并且您可能会重载operator =以做一些更花哨的事情,比如打印到控制台,或者锁定互斥锁,或者其他任何事情。

于 2010-05-28T04:31:50.890 回答
7

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

您可能还应该考虑“作为右值”是表达式的属性,而不是对象的属性这一事实。确实,T()表达式的计算结果为右值。尽管如此,表达式生成的临时对象T()仍然是一个object,它也可以作为左值访问。例如,可以在赋值的结果上调用其他一些成员函数,它会通过*thislvalue看到临时对象的“新”(新赋值)值

(T() = T()).some_member_function();

您还可以通过附加一个 const 引用来延长临时对象的生命周期,const T& r = T() = T();并且所看到的值r将是对象的“新”值。正如约翰内斯在他的评论中正确指出的那样,这不会将其附加到临时文件上。

于 2010-05-28T04:36:31.000 回答
5

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

class T
{
public:
    T& operator=(const T&) & = default;
};
于 2010-05-28T07:38:15.743 回答
4

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

// bit reference:
class reference {
  friend class bitset;
  reference();
public:
  ˜reference();
  reference& operator=(bool x);           // for b[i] = x;
  reference& operator=(const reference&); // for b[i] = b[j];
  bool operator˜() const; // flips the bit
  operator bool() const;  // for x = b[i];
  reference& flip();      // for b[i].flip();
};

reference operator[](size_t pos); // for b[i];

如果你这样做 bits[i] = true,你会为类类型的右值准确地分配一些值。返回的代理operator[]可以访问空间有效地打包成整数的位。

于 2010-05-28T17:57:26.030 回答
4

从一个 POV 来看,它是不一致的,但您忽略了它如何一致的:1) int 和其他内置类型的行为仍然与它们在 C 中的行为相同,2) 类类型上的 operator= 行为与任何其他方法没有的行为相同需要另一种特殊情况。

自 C++ 开始以来,C 兼容性一直受到高度重视,如果没有它,C++ 可以说今天不会出现。所以这部分通常是一件好事。

第二点被低估了。不特殊的大小写 operator= 允许无意义的代码“工作”,但为什么我们首先要关心无意义的代码呢?垃圾进垃圾出。就我所见,目前的规则赋予了它一个明确的含义(这里的 UB 会很糟糕),而且成本可以忽略不计。

鉴于我的德鲁特人,事情将进一步简化,因此int() = int()是允许的。C++0x 开始朝着这个方向发展,包括右值引用、纯右值等。

于 2010-05-28T07:05:10.503 回答