c++ - 将 unique_ptr 分配给第一个内的另一个 unique_ptr 是否安全?

标签 c++ unique-ptr

这个问题令人困惑,所以这里是我正在尝试做的事情的精简版:

#include <memory>
#include <iostream>

class A {
};

class B : public A {
    public:
        std::unique_ptr<A> a;
};

class C : public A {
    public:
        int var;
};

int main()
{
    C* c = new C;
    B* b = new B;
    c->var = 3;
    b->a = std::unique_ptr<A>(c);
    std::unique_ptr<A> aa(b);
    aa = std::move(static_cast<B*>(aa.get())->a);
    std::cout << static_cast<C*>(aa.get())->var;
}

我是这样做的:
- 创建一个自身拥有 unique_ptr 的类(我的具体情况是多态的,所以这就是我在这里所做的)
- 为该类创建一个 unique_ptr
- 将外部 unique_ptr 赋值给内部的 unique_ptr

现在,最后一步将销毁 unique_ptr 指向的对象。我分配给它的值是那个即将被删除的对象中的东西。但是,通过移动它,它可能不再在那里了。

虽然这段代码编译和运行良好(在 valgrind 中也是如此),但我想知道:这安全吗?是不是发生了什么我没有意识到的坏事?这样做有什么注意事项吗?

编辑:我忘了放入虚拟析构函数。假装所有三个类(class)都有。它在我的实际代码中。

最佳答案

这是安全的。

根本问题是unique_ptr 的移动赋值是如何工作的。请注意,一个更简单的示例(不涉及继承)演示了与您的代码相同的问题,它是使用 unique_ptr 的单链表:

class Node {
  public:
    unique_ptr<Node> next;
};

// ....

list_head = make_unique<Node>();
list_head->next = make_unique<Node>();
// Delete the head:
list_head = list_head->next;

关键问题是,旧*list_head节点的销毁(作为赋值操作的一部分发生)是否也会导致正在提升为头节点的节点销毁?

请注意,如果 unique_ptr 无法处理这种简单的情况,那将是非常令人惊讶的!

根据 CppReference,赋值运算符 behaves "as if by calling reset(r.release())" .这意味着 r(右侧,在本例中为最初拥有被提升节点的 unique_ptr)在 之前释放对象的所有权左侧 unique_ptr 已设置。

删除最初由分配给 unique_ptr 拥有的对象实际上是该过程中发生的最后步骤。在链表示例中,被删除的对象(旧头节点)在被销毁时已经有一个移出的unique_ptr


风格注释:

在代码中使用原始指针 bc 令人惊讶和困惑;当存在原始指针时,最终拥有 *b*cunique_ptr语义上不是唯一的指向拥有的对象。 (unique_ptr::get() 确实很有用——这里的奇怪之处在于您在同一范围内有多个指针指向相同的对象。)

newunique_ptr 一起使用是合理的,但不是“最佳实践”。我建议随时随地使用 make_unique。这在异常安全方面有好处,但在我看来,它在语义上也更清晰。

关于c++ - 将 unique_ptr 分配给第一个内的另一个 unique_ptr 是否安全?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42542331/

相关文章:

c++ - 具有空值和自定义删除器的 shared_ptr 奇怪

c++ - 使用 std::accumulate 计算 vector 元素总和的最准确方法是什么?

C++最佳实践: Returning reference vs.对象

c++ - 如何将 Oracle DB 中的 TIMESTAMP 列转换为 C++(MFC 或 WIN32)?

c++ - 在 main 内部创建的线程和在函数内部创建的线程的行为是否应该不同?

c++ - 无法在 C++ 中使用 unique_ptr 返回派生类型

c++ - 调整大小std::vector <std::unique_ptr <T >>的性能

c++ - 在 Linux 上使用 libserial 将 ASCII 控制字符发送到串行设备

c++ - 当在类主体中使用 unique_ptr 声明析构函数作为同一类的成员时出现编译器错误

c++ - 通过函数时的 unique_ptr 行为