6

C++ 草案指出:

12.8p31 这种复制/移动操作的省略,称为复制省略,在以下情况下是允许的(可以结合起来消除多个副本):

(...)

  • 尚未绑定到引用(12.2) 的临时类对象将被复制/移动到具有相同 cv-unqualified 类型的类对象时,可以通过将临时对象直接构造到目标中来省略复制/移动操作省略的复制/移动

换句话说:

X MakeX() {
   return X(); // Copy elided
}

X MakeX() {
   const X& x = X(); // Copy not elided
   return x;
}

限制引用的原因是什么

请不要关注以下示例的有效性,因为它们只是为了说明我看不到临时和参考之间的区别(恕我直言)

一方面,通过引入引用,我们允许其他对等方为同一个对象起别名,而调用者MakeX()希望它是安全和干净的。

class Y {
public:
    Y(const X& x) : _xRef(x) {}
private:
    const X& _xRef;
};

X MakeX() {
    const X& x = X();
    Y y{x};
    StaticStuff::send(y);
    return x; // Oops, I promised to return a clean,
              // new object, but in fact it might be silently
              // changed by someone else. 
}

但是这种情况呢(可能是 UB ;)):

class Y {
public:
    Y(X* x) : _xPtr(x) {}
private:
    X* _xRef;
};

X MakeX() {
    X x;
    Y y{&x}; // I'm referencing a local object but I know it will be
             // copy elided so present in the outer stack frame.
    StaticStuff::send(y);
    return x; // Copy elided?
}
4

1 回答 1

3

你永远不知道副本会被删除。复制省略从来都不是强制性的。

因此,要么这两种情况都是 UB,要么都没有。这取决于StaticStuff:send您传入的对象的作用。如果它保留对y._xRefor的任何*y._xPtr指针/引用,那么在返回后取消引用该指针/引用MakeX()确实会导致 UB,因为原始对象x是一个内部具有自动存储持续时间MakeX()及其生命周期的对象现在已经结束。

此 UB 的结果可能是“一切正常”,因为确实发生了复制省略,并且指针/引用引用了“外部堆栈帧”中的实例。然而,这纯属巧合,它仍然是 UB。

于 2013-04-08T08:25:34.960 回答