gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-11-30 02:26:35 27 4
gpt4 key购买 nike

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

#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/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com