web-dev-qa-db-fra.com

C ++ - en utilisant la référence const pour prolonger un membre d'un temporaire, ok ou UB?

considérez quelque chose comme ceci:

#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);
}

quand je compile avec -O0 je reçois l'impression

C ctor 56.32 11.99

mais quand je compile avec -O2 je reçois

 C ctor 0 0

Je sais que nous pouvons utiliser la référence const pour prolonger un temporaire local, donc quelque chose comme

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

serait parfaitement légal. mais j'ai du mal à trouver la raison pour laquelle le même mécanisme/règle ne s'applique pas à tout type de temporaire

MODIFIER POUR RÉFÉRENCE FUTURE:

J'utilise la version 6.3.0 de gcc

37
user2717954

Votre code doit être bien formé, car pour temporaires

(c'est moi qui souligne)

Chaque fois qu'une référence est liée à un temporaire ou à un sous-objet de celui-ci, la durée de vie du temporaire est étendue pour correspondre à la durée de vie de la référence

Étant donné A().b[4], b[4] Est le sous-objet de b et le membre de données b est le sous-objet du temproray A(), dont la durée de vie devrait être prolongée.

EN DIRECT sur clang10 avec -O2
EN DIRECT sur gcc10 avec -O2

BTW: Cela semble être un bug de gcc qui a été corrigé.

De la norme, [class.temporary]/6

Le troisième contexte est lorsqu'une référence est liée à un objet temporaire.6 L'objet temporaire auquel la référence est liée ou l'objet temporaire qui est l'objet complet d'un sous-objet auquel la référence est liée persiste pendant toute la durée de vie de la référence si la valeur gl à laquelle la référence est liée a été obtenue par l'un des éléments suivants :

...

[ Exemple:

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

- exemple de fin]

33
songyuanyao

A (). B [4] n'est pas un temp ou une rvalue, c'est pourquoi cela ne fonctionne pas. Alors que A() est temporaire, vous créez une référence à un élément de tableau qui existe au moment de la création. Le dtor déclenche alors pour A (), ce qui signifie l'accès ultérieur à bb devient un comportement quelque peu indéfini. Vous devez conserver le A & pour vous assurer que le b reste valide.

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