С++ Объект удалён, но добраться можно, почему так?
class A
{
public:
int d = 4;
};
int main( )
{
A *a = new A();
cout << a->d << endl;
A* p = &(*a);
delete a;
p->d = 5;
a->d=3;
cout << a->d << endl;
return 0;
}
Поясните пожалуйста этот код. По какой причине p->d работает даже после удаления a? То есть после delete если сразу вывести p->d, там будет мусорное значение.
Верно ли я понимаю, что p попросту указывает на некоторую область памяти, и компилятор(при создании указателя) "узнал", как обрабатывать выражения типа p->d, и дальше ему уже без разницы, есть ли там реально какой-то объект, к которому мы собираемся обращаться другим способом?
И дальше в коде p можно продолжать использовать как указатель на объект? или мы рискуем получить какие-то конфликты с памятью?
Что именно делает delete? Вопрос задан с целью разобраться, что именно происходит. Прилагаю ассемблерный код.
A::A() [base object constructor]:
push rbp
mov rbp, rsp
mov QWORD PTR [rbp-8], rdi
mov rax, QWORD PTR [rbp-8]
mov DWORD PTR [rax], 4
nop
pop rbp
ret
main:
push rbp
mov rbp, rsp
push rbx
sub rsp, 24
mov edi, 4
call operator new(unsigned long)
mov rbx, rax
mov DWORD PTR [rbx], 0
mov rdi, rbx
call A::A() [complete object constructor]
mov QWORD PTR [rbp-24], rbx
mov rax, QWORD PTR [rbp-24]
mov eax, DWORD PTR [rax]
mov esi, eax
mov edi, OFFSET FLAT:_ZSt4cout
call std::basic_ostream<char, std::char_traits<char> >::operator<<(int)
mov esi, OFFSET FLAT:_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_
mov rdi, rax
call std::basic_ostream<char, std::char_traits<char> >::operator<<(std::basic_ostream<char, std::char_traits<char> >& (*)(std::basic_ostream<char, std::char_traits<char> >&))
mov rax, QWORD PTR [rbp-24]
mov QWORD PTR [rbp-32], rax
mov rax, QWORD PTR [rbp-24]
test rax, rax
je .L3
mov esi, 4
mov rdi, rax
call operator delete(void*, unsigned long)
.L3:
mov rax, QWORD PTR [rbp-32]
mov DWORD PTR [rax], 5
mov rax, QWORD PTR [rbp-24]
mov DWORD PTR [rax], 3
mov rax, QWORD PTR [rbp-24]
mov eax, DWORD PTR [rax]
mov esi, eax
mov edi, OFFSET FLAT:_ZSt4cout
call std::basic_ostream<char, std::char_traits<char> >::operator<<(int)
mov esi, OFFSET FLAT:_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_
mov rdi, rax
call std::basic_ostream<char, std::char_traits<char> >::operator<<(std::basic_ostream<char, std::char_traits<char> >& (*)(std::basic_ostream<char, std::char_traits<char> >&))
mov eax, 0
mov rbx, QWORD PTR [rbp-8]
leave
ret
__static_initialization_and_destruction_0(int, int):
push rbp
mov rbp, rsp
sub rsp, 16
mov DWORD PTR [rbp-4], edi
mov DWORD PTR [rbp-8], esi
cmp DWORD PTR [rbp-4], 1
jne .L7
cmp DWORD PTR [rbp-8], 65535
jne .L7
mov edi, OFFSET FLAT:_ZStL8__ioinit
call std::ios_base::Init::Init() [complete object constructor]
mov edx, OFFSET FLAT:__dso_handle
mov esi, OFFSET FLAT:_ZStL8__ioinit
mov edi, OFFSET FLAT:_ZNSt8ios_base4InitD1Ev
call __cxa_atexit
.L7:
nop
leave
ret
_GLOBAL__sub_I_main:
push rbp
mov rbp, rsp
mov esi, 65535
mov edi, 1
call __static_initialization_and_destruction_0(int, int)
pop rbp
ret
Ответы (1 шт):
Это работает только из-за того, что вам повезло. Судя по всему перед этим куском памяти был другой кусок, который принадлежал вашему процессу. Потому менеджер памяти ничего вам не сказал. Был бы перед этим куском памяти другой кусок памяти, который бы принадлежал другому процессу - вам бы не удалось ничего в него записать (Это можно сделать, но не так).