与 std::unique_ptr 相关的错误

Posted

技术标签:

【中文标题】与 std::unique_ptr 相关的错误【英文标题】:Error associated with std::unique_ptr 【发布时间】:2014-07-11 10:24:06 【问题描述】:

我遇到了 std::unique_ptr 的问题。我以为我理解他们,但显然没有。

我有以下代码:

X::X() : m_foo(nullptr),

    m_foo = std::unique_ptr<Foo>(new Foo());


X::X(Foo* foo) : m_foo(nullptr),

    m_foo = std::unique_ptr<Foo>(foo);


std::unique_ptr<Foo> m_foo;

当我按如下方式构造 X 时:

Foo foo;
X x(&foo);

我在运行时收到一个错误,告诉我“对象 0x101f7eec0 的错误:未分配指针被释放”。

但是,当我按如下方式构造 X 时:

Foo foo;
X x;

不会发生这样的错误。

如果我添加以下析构函数:

X::~X()

    m_foo.release();

一切正常。

我不确定为什么首先会发生错误,也不确定为什么释放 foo 会清除它。

请有人解释一下。

【问题讨论】:

除了 ComicSansMS 的答案,您不需要将m_foo 初始化为nullptr,然后为其分配一个新构造的std::unique_ptr&lt;Foo&gt;。您可以立即使用正确的指针初始化m_foo,分别使用m_foo(new Foo())m_foo(foo)。显式成员初始化器的全部意义在于避免成员构造跟随赋值反模式。 【参考方案1】:

std::unique_ptr 用于管理动态分配对象(即使用new 等创建的对象)的生命周期。

在您失败的示例中,foo 是使用自动存储创建的,因此无需管理其生命周期(无论如何尝试这样做都会导致您观察到的错误)。一旦超出范围,编译器会自动销毁它。

【讨论】:

你是说我不能从原始指针创建 unique_ptr 吗? @ksl 可以,但是这样做会将指针的所有权转移到 unique_ptr。因此,unique_ptr 将在您销毁 unique_ptr 后尝试在指针上调用 delete(或调用自定义删除器,如果指定)。 而且您不能对在堆栈上创建的对象调用 delete - 这就是您的意思吗?因此,通过在析构函数中释放 foo,您可以有效地告诉编译器不要调用 delete。是对的吗?我还假设不会导致内存泄漏,因为 unique_ptr 将在 X 被销毁时被销毁,而 foo 将在调用者超出范围时被销毁? @ksl 是的,您不想对未使用new 分配的对象调用 delete。关键是,如果对象是在堆栈上分配的,则首先不需要unique_ptr。只需使用原始指针或引用来传递它。如果你想暗示所有权,只使用unique_ptr,也就是说,当unique_ptr死亡时应该被删除的对象。【参考方案2】:

当你这样做时

Foo foo;
X x(&foo);

foo 在堆栈中分配。堆栈中的对象不能包含在 unique_ptr 中。只有当对象在堆中时才可以这样做:

Foo* foo = new Foo( );
X x( foo );

【讨论】:

以上是关于与 std::unique_ptr 相关的错误的主要内容,如果未能解决你的问题,请参考以下文章

错误:使用已删除的函数‘std::unique_ptr<...> [关闭]

为啥 std::unique_ptr 重置与赋值不同?

将 std::unique_ptr 的子类与 std::variant 一起使用

如何将 std::sort() 与 std::unique_ptr<[]> 一起使用?

std::unique_ptr 作为参数在 std::thread 中起作用 [重复]

boost::ptr_vector 与 std::vector<std::unique_ptr<T>>? [关闭]