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<int>
,这样您不要得到三违规则。我真的不明白您为什么要尝试在 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 所有权疯狂的主要内容,如果未能解决你的问题,请参考以下文章
将所有权从 unique_ptr<T,void(*)(T*)> 转移到 unique_ptr<const T,void(*)(const T*)>