c++ - 关于将 const 引用绑定(bind)到临时对象的子对象

标签 c++ language-lawyer

代码如下

#include <stdio.h>

struct P2d {
    double x, y;
    P2d(double x, double y) : x(x), y(y) {}
    ~P2d() { printf("Destructor called\n"); }
};

P2d center() {
    return P2d(10, 10);
}

int main(int argc, const char *argv[]) {
    const double& x = center().x;
    printf("x = %.18g\n", x);
    return 0;
}

g++(版本 5.2.0)将在 中输入 printf 之前销毁 P2d 临时实例 main,但该值无论如何都会被保留(即,不是将 x 绑定(bind)到临时 P2d 实例的实际成员,而是创建 另一个临时的 double 来复制成员的值)。

clang++(IMO 正确)改为将临时 P2d 实例的生命周期延长到 x 引用的生命周期,析构函数将是因此在 main 中调用 after printf

如果不是使用普通 double 作为 xy 成员的类型,而是创建一个类(例如 Double) 然后两个编译器都同意,他们将临时 P2d 对象的生命周期延长到 printf 之后。

这是 g++ 中的错误还是标准允许的错误?

最佳答案

CWG 1651 涵盖了这一点:

The resolution of issues 616 and 1213, making the result of a member access or subscript expression applied to a prvalue an xvalue, means that binding a reference to such a subobject of a temporary does not extend the temporary's lifetime. 12.2 [class.temporary] should be revised to ensure that it does.

现状是only prvalues are treated as referring to temporaries - 因此 [class.temporary]/5 (“第二个上下文是当引用绑定(bind)到临时对象时。”)不被认为是适用的。不过,Clang 和 GCC 并未实际执行问题 616 的决议。 center().x is treated as a prvalue by both .我的最佳猜测:

  • GCC 根本没有对任何 DR 使用react。使用标量子对象 时不会延长生命周期,因为[dcl.init.ref]/(5.2.1.1)涵盖这些对象。所以完整的临时对象不需要继续存在(参见 aschelper's answer ),它不需要,因为引用不直接绑定(bind)。如果子对象是类或数组类型,则引用直接绑定(bind),GCC 会延长临时对象的生命周期。这已在 DR 60297 中注明。 .

  • Clang 识别成员访问并实现了“新的”生命周期延长规则 - 它甚至 handles casts .从技术上讲,这与其处理值(value)类别的方式不一致。但是,一旦上述 DR 得到解决,这将更加明智并且是正确的行为。

因此我会说 GCC 目前的措辞是正确的,但目前的措辞有缺陷且含糊不清,Clang 已经实现了 DR 1651 的未决决议,即 N3918 .本文非常清楚地涵盖了示例:

If E1 is a temporary expression and E2 does not designate a bit-field, then E1.E2 is a temporary expression.

center() 是根据论文对 [expr.call]/11 的措辞的临时表达式。因此,其在上述 [class.temporary]/5 中的修改后的措辞适用:

The second context is when a reference does not bind directly (8.5.3 dcl.init.ref) or is initialized with a temporary expression (clause 5). The corresponding temporary object (if any) persists for the lifetime of the reference except: [...inapplicable exceptions...]

瞧,我们有生命周期延长。注意“对应的临时对象”不够明确,是提案延期的原因之一;一旦修改,一定会被采纳。


is an xvalue (but not a bit-field), class prvalue, array prvalue or function lvalue and “cv1 T1” is reference-compatible with “cv2 T2”, or […]

事实上,GCC 完全尊重这一点,如果子对象具有数组类型,它将延长生命周期。

关于c++ - 关于将 const 引用绑定(bind)到临时对象的子对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50122583/

相关文章:

c++ - 为什么 common_type<long, unsigned long>::type = long long?

c++ - reinterpret_cast 从原始内存中获取的指针重新分配是否会导致 UB?

c++ - gcc模板错误

c++ - 将 argv 转移到一个新数组中

C++将文件的所有字节放入char数组?

c++ - 为什么在同一个作用域中声明多个相同的名称会导致程序格式错误?

c++ - 为什么 'typeid(x) == typeid(y)'评估为true,而 'x'和 'y'分别是类型T和T&的id表达式?

C++数组语法(函数返回数组)

c++ - 如何从 while 循环中添加数字?

一对指向采用不同类型参数的不同函数的指针可以兼容吗?