web-dev-qa-db-ja.com

C ++-const参照を使用して一時、OK、またはUBのメンバーを延長しますか?

次のようなものを検討してください:

#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を使用しています

37
user2717954

temporaries のため、コードは整形式である必要があります

(強調鉱山)

参照が一時またはサブオブジェクトにバインドされている場合は常に、一時の有効期間が延長され、参照の有効期間と一致します。

A().b[4]を指定すると、_b[4]_はbのサブオブジェクトであり、データメンバーbはtemproray A()のサブオブジェクトであり、その寿命は拡張する必要があります。

-O2を使用したclang10でのライブ
-O2を使用したgcc10でのライブ

ところで:これは修正されたgccの bug のようです。

標準から、 [class.temporary]/6

3番目のコンテキストは、参照が一時オブジェクトにバインドされている場合です。6 参照がバインドされている一時オブジェクト、または参照がバインドされているサブオブジェクトの完全なオブジェクトである一時オブジェクトは、参照がバインドされている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
_

—例を終了]

33
songyuanyao

A()。b [4]はtempまたはrvalueではないため、機能しません。 A()は一時的なものですが、作成時点で存在する配列要素への参照を作成しています。その後、dtorがA()をトリガーします。これは、後でbbにアクセスすることを意味しますbが有効なままであることを確認するには、A&を保持する必要があります。

    const A& a = A();
    const B& b = a.b[4];
    C c(b.x, b.y);
0
robthebloke