【问题标题】:How come it is possible to put a pointer twice in a vector of unique_ptr?为什么可以将指针两次放入 unique_ptr 的向量中?
【发布时间】:2021-04-06 22:42:55
【问题描述】:

std::unique_ptr不应该防止出现这种错误的可能性吗?

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

struct B {
    int b;
};

int main()
{
    std::vector<std::unique_ptr<B>> v;  // unique_ptr can be stored in a container
    B* p = new B;
    v.emplace_back(p);
    std::cout << "p:" <<p <<"\n";
    std::cout << "v[0]:"<<v[0].get() << "\n";
    v.emplace_back(p);
    std::cout << "p:" <<p <<"\n";
    std::cout << "v[1]:"<<v[1].get() << "\n";

}

检测到双重释放时的错误消息:

*** Error in `./a.out': double free or corruption (fasttop): 0x0000000001094c20 ***
======= Backtrace: =========
/lib/x86_64-linux-gnu/libc.so.6(+0x777e5)[0x7f3da200b7e5]
...
======= Memory map: ========
00400000-00402000 r-xp 00000000 ca:01 3228321                            /tmp/1617748074.6996937/a.out
...             

忽略双重释放时的输出:

p:0x1094c20
v[0]:0x1094c20
p:0x1094c20
v[1]:0x1094c20

【问题讨论】:

  • 你应该只将一个特定的单个指针放入一个 unique_ptr once。当你这样做时,它认为它拥有它,并将释放它。它不知道你已经把它放入了一些other unique_ptr。你不能那样做。 (想想它如何可能防止您所描述的情况:每个 unique_ptr 都必须知道 所有其他 unique_ptrs 您必须确保它是唯一持有它所持有的东西的人?不。它是在你正确使用它。)
  • 它应该像这样工作。您从同一个原始指针构造两个唯一指针,因此两者都尝试在最后释放它
  • 请记住,指针是单向的。没有机制让指针知道还有谁在指向一个对象 shared_ptr 甚至不知道还有谁在指向。它只知道计数。
  • 建议:通过虔诚地使用std::make_unique来避免这种可能性。
  • C++ 不会阻止你做错事

标签: c++ c++17 unique-ptr


【解决方案1】:

std::unique_ptr如果使用得当,可以防止双重释放错误:

  • 永远不要创建拥有的原始指针;使用std::make_unique
  • 如果您必须绝对使用new 创建拥有原始指针( 从工厂函数调用私有构造函数),然后这样做 在立即将原始指针包装在 std::unique_ptr 什么都不做,例如 return std::unique_ptr&lt;Base&gt;(new Derived(...));
  • 请勿在任何其他上下文中使用采用原始指针的 std::unique_ptr 构造函数。

如果遵循这些准则,每个unique_ptr 将管理一个不由其他任何人管理的对象。如果不遵循它们,则可能会出现您观察到的错误,其中可以从同一个原始指针创建多个 unique_ptr 实例。两个实例都没有“意识到”您传递给它的原始指针已经由另一个实例拥有。如果unique_ptr 构造函数必须检查是否有其他人拥有该指针,则会为每个用户带来性能开销。我们使用 C++ 来避免这种不必要的开销。只要您遵循指南,就没有必要。

【讨论】:

    【解决方案2】:

    最小的例子(不需要vector):

    struct B {
        int b;
    };
    
    int main()
    {
        B* p = new B;
        std::unique_ptr<B> x(p);
        std::unique_ptr<B> y(p);
    }
    

    您有两个unique_ptrs,他们认为他们拥有相同的原始指针。他们都将在该指针上调用delete,您将获得双倍免费。将unique_ptrs 放入容器并不会改变这一点。

    【讨论】:

    • 很好的简化。我已提交从x(b)x(p) 的更改。在原始错误版本中,您有std::unique_ptr&lt;B&gt; x(b); 出了什么问题。但是,必须先获得批准。
    猜你喜欢
    • 2021-03-11
    • 2015-11-28
    • 2014-01-02
    • 1970-01-01
    • 2021-10-27
    • 2019-01-22
    • 2017-06-12
    • 1970-01-01
    • 2014-05-25
    相关资源
    最近更新 更多