以下代码向函数modify_entry
传递指向类型为Entry
的对象的指针,并且在函数体{a} 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 / final)
目标:x86_64-apple-darwin13.1.0
线程模型:posix
它运行时没有错误,输出是
John的构造函数
在modify_entry()
中John Doe的析构函数
返回modify_entry()
John Doe
Here但是,由于第25行,我收到运行时错误。
问:当我运行clang生成的可执行文件时,为什么没有运行时错误?
如果有人能澄清情况,我真的很感激。请注意,我并未尝试正确转让所有权。这个设计的错误代码示例是调试过程的副产品。 make_unique
并移动unique_ptr
等的语义很棒,但这不是我要问的。
提前致谢。
答案 0 :(得分:6)
问:运行clang生成的可执行文件时,为什么没有运行时错误?
因为未定义的未定义行为。程序在其生命周期结束后尝试访问该对象。 C ++没有为这些程序定义任何行为。
make_unique
移动unique_ptr
等的语义很棒,而这样的事情只是你应该使用它们的另一个原因。
答案 1 :(得分:6)
但是,指针指向的对象似乎在函数返回后仍然存在。
这里的关键是&#34;似乎&#34;。实际上,Entry
的生命周期在此行的末尾结束:
std::unique_ptr<Entry>{e_ptr}->name_ += " Doe";
unique_ptr
取得了内存的所有权,但临时unique_ptr
的生命周期在该语句的结尾处结束,因此它也会删除它Entry
拥有。访问以前由对象使用的内存是未定义的行为。它适用于某些平台而非其他平台只是未定义行为的本质。
答案 2 :(得分:3)
因为您正在做的是undefined behavior,所以在main
函数中使用指向被破坏对象的指针。
对象被破坏(删除),但你仍然有一个指向 的指针,解除引用此指针是导致未定义行为的原因。