unique_ptr 所有权疯狂

Posted

技术标签:

【中文标题】unique_ptr 所有权疯狂【英文标题】:unique_ptr ownership craziness 【发布时间】:2020-02-01 19:00:42 【问题描述】:

看看下面的示例代码和它的输出。

我有一个简单的 Base 类,其中只有一个 int* 成员变量。

我从现有的 Base 对象创建了一个 unique_ptr。

当指针和对象超出范围时, 析构函数被调用了两次,首先是针对 unique_ptr,然后是针对对象。

我认为 unique_ptr 会拥有该对象并负责销毁它??

#include <iostream>
#include <string>
#include <vector>
#include <memory>

class Base

protected:
    int* status;

public:
    // default constuctor
    Base() : Base(0)
    
    

    // custom constuctor
    Base(int a)
        this->status = new int(a);
        std::cout << "\n" << "Base:" << *status;
    

    // destructor
    ~Base()
        std::cout << "\n" << "Base Destroyed:" << *status;
        delete this->status;
    

    void info()
        std::cout << "\n" << "Base status:" << *status;
        
;

int main(int argc, const char * argv[])

    
        Base base(1);

        // create from existing object
        std::unique_ptr<Base> uptrBase1 = std::make_unique<Base>(base);

        // create from new
        std::unique_ptr<Base> uptrBase3 = std::make_unique<Base>();

        std::cout<<"\n" << "Ending scope";
    

    std::cout<<"\n";
    return 0;

我得到的输出如下:

Base:1
Base:0
Ending scope
Base Destroyed:0
Base Destroyed:1
Base Destroyed:0TestCppProject(4373,0x1000d5dc0) malloc: *** error for object 0x1005ac970: pointer being freed was not allocated
TestCppProject(4373,0x1000d5dc0) malloc: *** set a breakpoint in malloc_error_break to debug
Program ended with exit code: 9

【问题讨论】:

unique_ptr 无关。你需要遵守“三法则”(或“五法则”)。 假设甚至没有将status 成员直接设为int 类型而不是int*,您应该将status 成员设为std::unique_ptr&lt;int&gt;,这样您不要得到三违规则。我真的不明白您为什么要尝试在 main 中使用 std::unique_ptr (至少基于您显示的示例)毫无意义,但您却没有在有影响的地方使用它。 @walnut 这段代码没有真正的目的,只是为了演示 unique_ptr 的行为 添加您的复制和移动操作并观察它们打印的内容。这将允许您可视化编译器生成的其他成员。 【参考方案1】:

我认为 unique_ptr 会拥有该对象并负责销毁它??

您不能取得自动存储期限对象的所有权。此类对象的生命周期由编译器控制,并在它们定义的块的末尾结束。时期。这一行的作用:

std::unique_ptr<Base> uptrBase1 = std::make_unique<Base>(base);

它创建动态存储持续时间对象并使用base 对其进行初始化。即逻辑上这段代码等于:

Base *ptr = new Base( base );
std::unique_ptr<Base> uptrBase1( ptr );

所以你复制了base 并将这个新创建的对象的所有权交给uptrBase1。当您违反 What is The Rule of Three? 时,这会导致 UB,因为您在类 Base 中创建的内部指针被双重破坏,并且当您创建 3 个 Base 类型的对象时,它的析构函数被调用了 3 次。

顺便说一句:如果你遵循实践并 make status std::unique_ptr 编译器将不允许你违反规则并且前面提到的行将无法编译。

【讨论】:

在我实现了移动和复制构造函数之后,我看到了我在堆栈上定义的 Base 对象的复制是如何发生的。现在这是有道理的,因为发生了什么!我认为看看 unique_ptr 如何处理堆栈上的对象是一个很好的练习

以上是关于unique_ptr 所有权疯狂的主要内容,如果未能解决你的问题,请参考以下文章

尝试深度复制唯一指针时的 C++ 内存访问冲突

C++ 11 创建和使用 unique_ptr

将所有权从 unique_ptr<T,void(*)(T*)> 转移到 unique_ptr<const T,void(*)(const T*)>

我可以制作一个 unique_ptr 不获取其指向对象的所有权吗?

指向 std::unique_ptr 的内容

vector系列--vector<unique_ptr<;;初始化(所有权转移)