这种对共享指针向量的回退是不是会导致内存泄漏?

Posted

技术标签:

【中文标题】这种对共享指针向量的回退是不是会导致内存泄漏?【英文标题】:Does this pushback to a shared pointers vector causes memory leaks?这种对共享指针向量的回退是否会导致内存泄漏? 【发布时间】:2021-05-02 11:17:06 【问题描述】:

我正在为我所在的项目制作节点编辑器,并且我有一个 Node 的共享指针的 std::vector,该类具有不同节点类型的派生类。

正如我所说,这是一个共享指针向量(我正在试验智能指针,所以在这方面我有点新手),当我创建一个节点时,会执行下一个代码:

 DerivedNodeClass* d_node = new DerivedNodeClass();
 nodes.push_back(std::make_shared<Node>((Node*)d_node);

所以这工作正常,但我想知道这种创建节点的方式是否会导致内存泄漏或类似情况,因为我不确定这是否是创建类并将它们添加到向量中的“正确方式”智能指针。

在我停止使用节点后,我只是迭代调用.reset() 的向量,但我仍然不确定我是否做得对。

请注意,Node 的任何派生类都可以处理与动态内存相关的任何指针或任何内容。

【问题讨论】:

创建某些东西不会导致泄漏,但不删除它会。因此,仅通过查看构造就无法知道您的代码是否无泄漏。智能指针有很大帮助,但即使使用智能指针也有可能出错。为什么你认为你的代码会导致泄漏? 不相关但... (Node *) 演员表不应该是必需的。如果是这样,那么有一些可疑的事情发生了。 你为什么不用std::make_sharedauto d_node = std::make_shared&lt;DerivedNodeClass&gt;(); nodes.push_back(std::move(d_node));. @largest_prime_is_463035818 是的,对,对不起,删除后所有节点都被迭代并调用node[i].reset(),我将编辑问题。 @Evg 实际上,我使用make_shared,但我使用不同的选项对其进行了模板化,因此当我从代码中复制它时,我复制了错误的行,我也会对其进行修改:) 【参考方案1】:

您可能知道,共享指针会在最后一个共享指针停止指向数据的那一刻自行删除它们所指向的数据(最后一个引用被销毁 - 共享指针保存有关存储了多少个共享指针指向该数据的信息在内存中)。

在使用共享指针时,您可能会遇到内存泄漏问题的唯一方法是,例如,当您将 class Wrapper 作为 class Node 实例的容器时,其中存储在类 Wrapper 容器中的每个节点都有一个对 Wrapper 类的引用(作为 shared_ptr),并且从其他地方有一个 shared_ptr 指向 Wrapper 类的实例(从之前创建实例的地方)。这意味着 Wrapper 类的实例指向 Node 类的实例,同时 Node 类的实例指向 Wrapper 类的实例,并且还有另一个指向 Wrapper 类的实例的指针。 (我试图在这里为它画一个草图: before destruction, after destruction,它帮助我理解了智能指针)

当您尝试调用 Wrapper 类的析构函数时,它会从创建位置删除 shared_ptr,但容器中的每个 Node 实例都指向 Wrapper 实例。您试图破坏的 Wrapper 类的实例仍然存在 shared_ptr 。这意味着 shared_ptr 中有一个对此 Wrapper 类实例的引用因此销毁此实例将导致内存泄漏。

如果你想解决这个问题,你应该检查弱指针(https://en.cppreference.com/w/cpp/memory/weak_ptr)。 希望我能帮上忙。

【讨论】:

哇,感谢您的解释和草图,它对我帮助很大!根据你说的,那我不应该从这里发生内存泄漏。谢谢你:) 我更愿意直接在 make_shared 中调用构造函数,但这也应该没问题。

以上是关于这种对共享指针向量的回退是不是会导致内存泄漏?的主要内容,如果未能解决你的问题,请参考以下文章

memset向量为0会导致内存泄漏吗?

在函数中留下指针会导致内存泄漏吗?

在没有虚拟析构函数的情况下删除基类指针会导致内存泄漏吗?

C语言中的指针和内存泄漏

是啥导致了这种内存泄漏?

访问指向结构的指针会导致内存读取冲突