与 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<Foo>
。您可以立即使用正确的指针初始化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::variant 一起使用
如何将 std::sort() 与 std::unique_ptr<[]> 一起使用?