37

考虑这样的事情:

#include <iostream>

struct C {
    C(double x=0, double y=0): x(x) , y(y) {
        std::cout << "C ctor " << x << " " <<y << " "  << "\n";
    }
    double x, y;
};

struct B {
    B(double x=0, double y=0): x(x), y(y) {}
    double x, y;
};

struct A {
    B b[12];

    A() {
        b[2] = B(2.5, 14);
        b[4] = B(56.32,11.99);
    }
};


int main() {
    const B& b = A().b[4];
    C c(b.x, b.y);
}

当我用 -O0 编译时,我得到了打印

C ctor 56.32 11.99

但是当我用 -O2 编译时,我得到了

 C ctor 0 0

我知道我们可以使用 const 引用来延长本地临时,所以像

const A& a = A();
const B& b = a.b;

将是完全合法的。但我正在努力寻找为什么相同的机制/规则不适用于任何临时的原因

编辑以供将来参考:

我正在使用 gcc 版本 6.3.0

4

2 回答 2

34

您的代码应该格式正确,因为对于临时人员

(强调我的)

每当引用绑定到临时对象或其子对象时,临时对象的生命周期就会延长以匹配引用的生命周期

Given A().b[4],b[4]是temproray 的子对象,b数据成员b是 temproray 的子对象,A()应该延长其生命周期。

使用 -O2
在 clang10 上直播 使用 -O2 在 gcc10 上直播

顺便说一句:这似乎是一个已修复的 gcc错误。

从标准来看,[class.temporary]/6

第三个上下文是引用绑定到临时对象时。36如果绑定到引用的glvalue是通过以下之一获得的,那么引用绑定到的临时对象或作为引用绑定到的子对象的完整对象的临时对象将在引用的生命周期内持续存在下列的:

...

[ 例子:

template<typename T> using id = T;

int i = 1;
int&& a = id<int[3]>{1, 2, 3}[i];          // temporary array has same lifetime as a
const int& b = static_cast<const int&>(0); // temporary int has same lifetime as b
int&& c = cond ? id<int[3]>{1, 2, 3}[i] : static_cast<int&&>(0);
                                           // exactly one of the two temporaries is lifetime-extended

—结束示例]

于 2019-09-10T07:46:11.837 回答
1

A().b[4]不是 temp 或rvalue,这就是它不起作用的原因。虽然A()是临时的,但您正在创建对创建时存在的数组元素的引用。然后dtor触发 for A(),这意味着以后访问b.b变得有点未定义的行为。您需要坚持A&以确保b仍然有效。

const A& a = A();
const B& b = a.b[4];
C c(b.x, b.y);
于 2019-09-10T07:38:22.537 回答