在std :: unique_ptr超出范围后仍可访问对象。不同的运行时行为

时间:2014-04-15 14:16:43

标签: c++ c++11 unique-ptr dangling-pointer

以下代码向函数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等的语义很棒,但这不是我要问的。

提前致谢。

3 个答案:

答案 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函数中使用指向被破坏对象的指针。

对象破坏(删除),但你仍然有一个指向 的指针,解除引用此指针是导致未定义行为的原因。