Инвалидация структуры с константной ссылкой-полем

Здесь:

using namespace std;

struct S
{
    int x;
    const int &y;
};

int main()
{
    //S x{1,2};
    S* p = new S{1,2};
    return 0;
}

Здесь с p всё нормально, но что с y? Говорят, теперь второе поле этой структуры не валидно. Так писано в стандарте: во отличие от закомментированной строки, полное выражение кончается на new, и объект (2), которому продлили жизнь, всё равно помер.

Но в чём именно это проявляется? Я могу вывести ((*p).y) и получить 2, могу взять адрес от этого выражения.

То есть, Как это понять? Какие проблемы будут? В каком коде будет разница при общении с x и *p ?


Ответы (1 шт):

Автор решения: AlexGlebe

Смотрим ассемблерный код g++ -std=c++17 -O0 -S -fverbose-asm rvalp.cpp :

        movq    %rsp, %rbp      #,
        pushq   %rbx    #
        subq    $24, %rsp       #,
# rvalp.cpp:10:     S* p = new S{1,2};
        movl    $2, -28(%rbp)   #, D.2080
        leaq    -28(%rbp), %rbx #, _3
        movl    $16, %edi       #,
        call    _Znwm   #
        movl    $1, (%rax)      #, MEM[(struct S *)_6].x
        movq    %rbx, 8(%rax)   # _3, MEM[(struct S *)_6].y
        movq    %rax, -24(%rbp) # _5, p
# rvalp.cpp:11:     return 0;
        movl    $0, %eax        #, _11
# rvalp.cpp:12: }
        addq    $24, %rsp       #,
        popq    %rbx    #
        popq    %rbp    #
        ret

адрес стека копируем в rbp :

movq    %rsp, %rbp

временное число 2 храним в стеке :

movl    $2, -28(%rbp)

адрес этого места в стеке записываем в rbx :

leaq    -28(%rbp), %rbx

выделяем память для этого объекта :

call    _Znwm

записываем все элементы структуры по адресу rax :

movl    $1, (%rax)
movq    %rbx, 8(%rax)

В итоге ссылка const int &y; указывает на место в стеке, где хранился временный объект и любой дальнейший ход программы всё сотрёт. Так как адрес -28(%rbp) глубже адреса последней переменной -24(%rbp) p.


В случае S x{1,2}; временный объект 2 (-4(%rbp))будет хранится выше по стеку и затираться будет после переменной x (-24(%rbp)).

# rvalp.cpp:9:     S x{1,2};
    movl    $2, %eax        #, _1
    movq    $0, -32(%rbp)   #, x
    movq    $0, -24(%rbp)   #, x
    movl    $1, -32(%rbp)   #, x.x
    movl    %eax, -4(%rbp)  # _1, D.2091
    leaq    -4(%rbp), %rax  #, tmp90
    movq    %rax, -24(%rbp) # tmp90, x.y
→ Ссылка