为什么可以从另一个 unique_ptr get() 创建一个 unique_ptr 而不会导致错误?

Chl*_*uan 2 c++ smart-pointers unique-ptr

我对 C++ 和智能指针很陌生,尤其是 unique_ptr 的行为。下面是我正在试验的一段代码:

unique_ptr<int>  u1 = make_unique<int>(2);
unique_ptr<int>  u2 = make_unique<int>();
u2.reset(u1.get());
Run Code Online (Sandbox Code Playgroud)

根据定义,unique_ptr 是一种智能指针,它不与其他智能指针共享它所指向的对象的所有权。但是,为什么上面的代码没有返回错误呢?事实上,如果我尝试打印 u1 和 u2 的值,结果它们确实指向相同的内存地址:

cout<<u1.get()<<endl;
cout<<u2.get()<<endl;
Run Code Online (Sandbox Code Playgroud)

在控制台上显示这些:

0x55800839ceb0
0x55800839ceb0
free(): double free detected in tcache 2 // finally the error appears at the end of the program's execution
Run Code Online (Sandbox Code Playgroud)

但如果我说:

cout<<(*u1)<<endl;
(*u1)=5;
cout<<(*u2)<<endl;
Run Code Online (Sandbox Code Playgroud)

更改不会影响 (*u2),就好像它们位于不同的内存地址中一样。

任何帮助,将不胜感激!感谢您的时间!

ζ--*_*ζ-- 7

一旦你调用get(),你就有了一个原始指针。它只是一个指针,并且不携带标准库或语言可以保留或提供的重要所有权语义。

然后,您可以使用该指针使第二个唯一指针获得所指向对象的所有权。它“认为”它拥有该对象的唯一所有权。这完全没问题,只要该唯一指针确实是唯一拥有该对象的东西。

不幸的是,第一个唯一指针仍然拥有同一个对象,因此当两个唯一指针尝试破坏该对象时,将会出现双重释放。这是未定义的行为,并且不能保证在编译时提供清晰的错误消息。您可能会发生微妙的损坏、无声的崩溃,或者程序可能会偶然地无声地成功。

然而,当消毒剂启用时,它可以在运行时更可靠地显示明显的错误,因为它会积极地寻找某些类型的未定义行为。这是一个演示,展示了 ASan(Address Sanitizer)检测此双重释放,正如它的设计目的一样。

更改不会影响 (*u2),就好像它们位于不同的内存地址中一样。

确实如此;请参阅上面的演示,其中打印2 2 2 5u1u2u1更新前、更新u2后)。u1