1

下面的代码将modify_entry一个指向类型对象的指针传递给函数,Entry并且在函数体内 aunique_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 版 (tags/RELEASE_34/final)

目标:x86_64-apple-darwin13.1.0

线程模型:posix

它运行没有错误,输出是

约翰的构造函数

在 modify_entry() 内部

John Doe 的析构函数

从 modify_entry() 返回

约翰·多伊

但是,在这里,由于第 25 行,我收到了运行时错误。

Q:为什么运行clang生成的可执行文件没有运行时错误?

如果有人能澄清情况,我将不胜感激。请注意,我并没有尝试正确转让所有权。这个人为设计的错误代码示例是调试过程的副产品。make_unique并为等移动语义unique_ptr很棒,但这不是我要问的。

提前致谢。

4

3 回答 3

6

但是,指针指向的对象似乎在函数返回后仍然存在。

这里的关键是“似乎”。实际上,Entry的生命周期在这一行的末尾结束:

 std::unique_ptr<Entry>{e_ptr}->name_ += " Doe";

unique_ptr已经获得了内存的所有权,但是临时的unique_ptr生命周期在该语句的末尾结束,因此它也删除了Entry它拥有的。访问对象以前使用的内存是未定义的行为。它适用于某些平台而不适用于其他平台只是未定义行为的本质。

于 2014-04-15T14:28:44.313 回答
6

Q:为什么运行clang生成的可执行文件没有运行时错误?

因为未定义的行为是未定义的。程序在其生命周期结束后尝试访问对象。C++ 没有为此类程序定义任何行为。

make_unique和等的移动语义unique_ptr很棒,这样的事情只是你应该使用它们的另一个原因。

于 2014-04-15T14:20:27.187 回答
3

因为您所做的是未定义的行为,所以在main函数中使用指向已破坏对象的指针。

对象破坏(删除),但你仍然有一个指向它所位置的指针,取消引用这个指针是导致未定义行为的原因。

于 2014-04-15T14:21:07.780 回答