Объект все еще доступен после выхода из std::unique_ptr. Различное поведение во время выполнения
Следующий код переходит к функции modify_entry
указатель на объект типа Entry
и внутри тела функции а unique_ptr
принимает необработанный указатель. Однако объект, на который указывают указатели, кажется, продолжает жить после возврата из функции.
Когда я компилирую этот код
#include <iostream>
#include <memory>
struct Entry {
Entry(std::string name) : name_(name) { std::cout << "Constructor for " + name_ + '\n'; }
~Entry() { std::cout << "Destructor for " + name_ + '\n'; }
std::string name_;
};
void modify_entry(Entry* e_ptr){
std::cout << "Inside modify_entry()\n";
std::unique_ptr<Entry>{e_ptr}->name_ += " Doe";
}
int main(int argc, const char * argv[])
{
Entry* entry_ptr = new Entry("John");
modify_entry(entry_ptr);
std::cout << "Back from modify_entry()\n";
std::cout << entry_ptr->name_ << '\n'; // <---- line 25
return 0;
}
с
Clang версия 3.4 (теги /RELEASE_34/ финал)
Цель: x86_64-apple-darwin13.1.0
Модель потока: posix
Он работает без ошибок и вывод
Конструктор для Джона
Внутри modify_entry()
Разрушитель для Джона Доу
Вернуться из modify_entry()
Джон Доу
Здесь, однако, я получаю ошибку времени выполнения из-за строки 25.
Q: Почему при запуске исполняемого файла, созданного clang, не возникает ошибка времени выполнения?
Буду очень признателен, если кто-то сможет прояснить ситуацию. Обратите внимание, что я не пытаюсь правильно передать право собственности. Этот надуманный пример плохого кода является побочным продуктом процесса отладки. make_unique
и переместить семантику для unique_ptr
и т. д. отлично, но это не то, что я спрашиваю.
Заранее спасибо.
3 ответа
Однако объект, на который указывают указатели, кажется, продолжает жить после возврата из функции.
Ключевым моментом здесь является "кажется". На самом деле, Entry
Срок жизни заканчивается в конце этой строки:
std::unique_ptr<Entry>{e_ptr}->name_ += " Doe";
unique_ptr
завладела памятью, но временная unique_ptr
время жизни заканчивается в конце этого оператора, поэтому он также удаляет Entry
что он владеет. Доступ к памяти, которая ранее использовалась объектом, является неопределенным поведением. То, что он работает на некоторых платформах, а не на других, это просто природа неопределенного поведения.
Q: Почему при запуске исполняемого файла, созданного clang, не возникает ошибка времени выполнения?
Потому что неопределенное поведение не определено. Программа пытается получить доступ к объекту после окончания срока его службы. C++ не определяет поведение для таких программ.
make_unique
и переместить семантику для unique_ptr
и т. д. это здорово, и подобные вещи - это еще одна причина, по которой вы должны использовать это.
Потому что то, что вы делаете, это неопределенное поведение, когда в main
Функция, которую вы используете указатель на разрушенный объект.
Объект уничтожен (удален), но у вас все еще есть указатель на то, где он был, разыменование этого указателя приводит к неопределенному поведению.