Инвалидация структуры с константной ссылкой-полем
Здесь:
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 шт):
Смотрим ассемблерный код 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