Объект все еще доступен после выхода из 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 Функция, которую вы используете указатель на разрушенный объект.

Объект уничтожен (удален), но у вас все еще есть указатель на то, где он был, разыменование этого указателя приводит к неопределенному поведению.

Другие вопросы по тегам