【问题标题】:Pointers and collection of pointers in C++. How to properly deleteC++ 中的指针和指针集合。如何正确删除
【发布时间】:2025-12-04 23:40:01
【问题描述】:

这是一个新问题,但我一直怀疑 C++ 中的指针。情况就是这样。

我有一个类 A,它是 B 类指针的集合(实际上是一个向量)。同一个类 A 有另一个指向类 C 的指针集合。最后,类 B 的对象也有一个指向类指针的集合C 指向类 A 指向的相同实例。

我的问题是,如果我在 B 类中删除了一个 C 类类型指针的成员,那么 A 类中指向已删除的 C 类实例的指针会发生什么情况?这种情况该如何处理?

提前非常感谢!

朱伦。

【问题讨论】:

  • 请具体说明-您是删除指针还是指针指向的内存?
  • 我正在删除指针指向的内存。

标签: c++


【解决方案1】:

我的理解:

A
 - vector<B*>
 - vector<C*>

B
 - vector<C*>

从 B 中删除所有 C*。


您需要分别删除每个内存地址,但最多只能删除一次。

任何指向已删除地址的指针仍然持有相同的地址,如果使用它只会产生未定义的行为。

所以一定不要再从A中删除你已经删除的B*,并且一定不要在删除之后再使用它们。


不过,您可能需要重新考虑您的层次结构/设计。

如果您需要以这种方式存储东西,可以考虑使用boost::shared_ptr。实际上,只要您存储指针集合,您可能应该使用 boost::shared_ptr。如果您使用的是 boost::shared_ptr,则无需删除,也无需担心其他指针无效。

【讨论】:

  • +1 特别。与重新考虑的部分。共享所有权很少是一个好的解决方案。 shared_ptr 可能看起来很诱人,但恕我直言,它适用于特殊情况。当您发现自己需要对象的共享所有权时,请重新评估您的架构,看看是否真的需要共享所有权。
  • 更好的是unique_ptrs的集合,但只有最新版本的VC++和GCC才有unique_ptrs。
  • boost::shared_ptr 和可能boost::weak_ptr 结合使用,取决于实际语义(A 中的指针在从B 中删除时是否应该“无效”?)
  • 首先感谢大家的贡献。是的,我期待答案是这样的。问题是,就设计而言,我该如何改进这种层次结构。 B 类是 C 类的真正所有者,但同时我喜欢跟踪 A 类中 C 类的所有实例。(B 类知道一些 C 类实例,而不是全部)。问题是我没有“被允许”使用 boost,我想学习设计好的程序。
  • @Julen:如果不确切知道您要做什么,就很难说。但是请发布一个新问题,这样您就可以得到其他人的帮助。
【解决方案2】:

考虑使用合适的智能指针将原始指针保存在容器中,而不是直接使用原始指针,这样可以省去弄清楚如何手动删除它们的麻烦。如果您需要,这些通常还支持自定义释放函数和仿函数。您可以根据需要查看 shared_ptr 或 weak_ptr。您可能还会发现 unique_ptr 很有用,这完全取决于您的要求。

【讨论】:

  • 我想你的意思是:'shared_ptr 或 weak_ptr' 哈哈?
  • +1,但是您将如何在 shared_ptr 或 shared_ptr 之间进行选择?
  • 我将尝试回答 Polaris878 和 Pete 组合所暗示的问题。 shared_ptr 和weak_ptr 之间的区别。 shared_ptr 声明所有权,因此当最后一个 shared_ptr 放弃所有权时,该对象被销毁。 weak_ptr 声明没有所有权,因此不计入所有权声明。通常,对某物有一个 weak_ptr 意味着在某个地方也有一个对同一个对象的 shared_ptr。我们曾经有一个拓扑结构,其拓扑连接由weak_ptrs维护,节点列表由smart_ptrs维护。
【解决方案3】:

如果您从 B 类中删除 C 类的实例,那么 A 类中的指针仍然指向这些地址...导致未定义的行为(很可能是 seg 错误)。您必须确保如果您在一个位置删除一个实例,那么对该实例的所有其他引用也会更新。

在您的情况下,您希望将 A 的集合清除到 C 类。

另一种方法是使用智能指针...您可以对同一个实例有多个引用,并且只有在没有更多引用存在时才会删除该实例。

【讨论】:

    【解决方案4】:

    如果你删除类 C 中的指针指向的对象,实际上 什么都不会发生 指向其他类中相同对象的指针。也就是说,它们将保持与以前相同的值并指向一些已取消分配的内存。

    几种解决方案:

    • 编写代码以在从 C 类中删除时从其他用户类中删除指针
    • 使用智能指针,因此指向的对象只有在没有指针指向它们时才会被删除。

    我不太喜欢第二种解决方案,即使它很常见,因为它表明你的对象生命周期控制不佳。您可能应该重新考虑您的设计。

    【讨论】:

      【解决方案5】:

      如果你想使用指针和动态分配,你需要定义谁拥有什么。

      在你的情况下,从Bs 中删除Cs 是危险的,因为在Bs 被销毁后,他们已经带走了Cs,即使A 仍然有对它们的引用。

      在您的情况下,我会发现最好执行以下操作:

      • 销毁 C 没有任何作用
      • 摧毁一个 B 没有任何作用
      • 销毁 A 会销毁其 B 和 C 的集合

      表示A是内存的拥有者,管理着对象的生命周期,而Bs只有Cs的引用。

      另外,我建议使用 RAII(资源获取即初始化),以便为您自动完成清理工作:

      class A
      {
      public:
      private:
        std::vector< std::unique_ptr<B> > bs;
        std::vector< std::unique_ptr<C> > cs;
      };
      
      // B and C are unchanged
      

      使用unique_ptr有3个好处:

      • 它清楚地说明了内存的所有者是谁(在本例中为A 的实例)
      • 它可以防止意外复制 A 实例,这会严重破坏您的设计
      • 它简化了内存的处理,它是自动的,不用担心

      【讨论】:

        【解决方案6】:

        我会说你缺少的是 D 类。

        D 是拥有 A、B、C 的类。如果 C 对象是动态创建的,A 应该创建并存储它们,而 A 和 B 可以使用非托管指针。

        对于 D 的实现,boost::ptr_vector 可能是 C 对象的一个​​很好的容器,如果它们需要是指针形式(多态对象)或一个普通的向量来存放好的旧对象。

        【讨论】:

          【解决方案7】:

          当旧指针指向的内容被删除时,将旧指针设置为 NULL 总是一个好主意 - 除非您接下来要销毁指针列表。

          【讨论】:

          • 虽然这是个好建议,但在 @Julen 的情况下,将 B 的指针值设置为 NULL 不会更改 A 中的指针。
          • @Illusive:不,这不是是个好主意!这在 C 和 C++ 中都是不好的做法。这样做您只需将导致段错误的错误替换为导致内存泄漏的错误(通常非常更难找到)。同样在对象 A 中的指针的这种情况下,如果您删除另一个类中的指向对象,它们也不会被更改。使用 RAII 是一个更好的主意。
          • @kriss:是的,RAII 是最好的解决方案,但是说删除后将原始指针设置为 NULL 是不好的做法,充其量是可笑的。如果您必须处理原始指针,则绝对有必要将已删除或未使用的指针设置为 NULL。
          • 我想我没有以足够好的方式解释我的意思。我并不是说一旦删除了指针指向的对象/变量,就应该将每个指针都设置为 NULL。但是,在处理指针列表或将来可能再次指向已分配对象的指针时 - 有必要将指针设置为 NULL 以确保在分配新对象之前删除旧对象。此外,旧指针可能仍指向旧值,或者至少是“工作”值。在这种情况下,最好指向 NULL 并及时发现错误。
          • 必要时我的意思是你不能在以后检查指针是否指向一个对象。不过,很容易检查它是否指向 NULL。由于文本限制,我无法将其纳入我之前的评论中。