【问题标题】:Sequential new & delete顺序新建和删除
【发布时间】:2011-07-19 10:06:50
【问题描述】:

继续我的previous question,我想问以下问题:

给定一个 C++ 函数,其中包含一个新语句,但没有显式返回任何内容(即使用 return 语句),它是否也应该总是有一个删除?

如果不是,请给我一个例子。

【问题讨论】:

  • 每一个new 必须有一个匹配的delete,否则就会出现内存泄漏。
  • @FredOverflow:但不一定在同一个函数中。
  • @FredOverflow:他问的不是这个。
  • new 返回的指针可以分配给全局变量,也可以包裹在scoped_ptr 或其他任何东西中。所以,一般的答案是否定的。
  • 我问这个是因为我确定我的程序正在泄漏

标签: c++ return delete-operator


【解决方案1】:

它不必显式地返回新创建的对象,但它应该以某种方式将它传递给其他东西。可能的情况包括:

  • 在成员函数中,创建一个对象并将其分配给包含对象的字段。

例子:

class Foo {
    private:
        Baz* baz;
    public:
        Foo() : baz(0) { }
        void create_bar() { baz = new Baz(); }
        ~Foo() { delete baz; }
};
  • 将新对象传递给其他对象。

例子:

void foo() {
    // assuming bar lives in the global scope
    bar.baz = new Baz();
}

void foo2(Bar& bar) {
    bar.baz = new Baz();
    // or, better:
    bar.setBaz(new Baz());
}
  • 使用某种垃圾收集指针类型。

例子:

std::auto_ptr<Baz> foo() {
    return new Baz();
}
  • 将指针传递给另一个函数,该函数对其进行处理,然后将其删除。

例子:

void foo(Bar* bar) {
    bar->dostuff();
    delete bar;
}

void baz() {
    Bar* bar = new Bar();
    foo(bar);
}

【讨论】:

    【解决方案2】:

    new 的规则非常简单:new 返回的指针必须在代码中的某个位置被 someone 删除。如果new 返回的指针丢失、遗忘或丢弃,则说明存在内存泄漏,这很糟糕。

    因此,如果您new 占用了一些内存并返回而没有将其永久存储在任何地方,那么您已经泄漏了内存。因此,如果您不打算删除它,那么指针必须要么存储在某种长期存储中(类成员、静态变量等),要么必须返回以便其他人可以删除它.

    或者,您可以只使用 boost::shared_ptr 并停止关心(大部分)这个。

    【讨论】:

    • boost::shared_ptr 和类似的不是总是可用(例如在 C++ 游戏中经常出现),所以这些问题仍然存在。
    • @xan: s/available/fast enough/
    • 因为通常不允许外部库(例如 boost)进入代码库。因此,如果图书馆团队还没有推出自己的...显然这取决于团队以及就可用和内部图书馆和内存管理政策做出的决定。
    • @xan:很多游戏开发者都停留在 C++ 开发的“C with classes”心态中。如果这就是他们想要发展的方式,那取决于他们。但这并不否定这个建议。也不意味着他们不能使用它;他们只是选择不这样做。
    • @Nicol Bolas:是的,绝对是,只是举了一个仍然可以相关的领域的例子。干杯。
    【解决方案3】:

    如果您在函数中使用new 分配内存,并且该内存在函数外部(或静态)不可访问,则需要在函数存在之前将其释放。在这种情况下,我建议使用std::auto_ptr 或boost::scoped_ptr,因为它会在函数退出时为您调用delete。即使抛出异常。

    【讨论】:

      【解决方案4】:

      不,如果函数的目的是实例化一些数据并将其交给其他对象。来自游戏行业的(假设)示例:

      void AddProjectileAtPoint(int x, int y)
      {
          Projectile *p = new Projectile(x, y);
          mProjectileManager->Add(p); //"mProjectileManager"'s job is to hold all projectiles and update them every frame...
      }
      

      在这种情况下,明确的目的是创建一个表示某些数据的新对象并将其存储在某处以供以后使用。

      显然,需要有一个匹配的delete 在某些时候,但不在new 出现的函数内。只要有一个明确定义的程序将管理new'd 内存的责任传递给其他组件,这就可以了。

      在这种情况下,结构是“Projectile Manager”负责给它的所有射弹,只要需要,就会让它们保持活动状态,并在适当的时候清理内存。

      【讨论】:

        【解决方案5】:

        如果函数使用new 创建资源并且没有将指向该资源的指针传递回任何东西,那么是的,它必须删除该资源,否则它永远不会被清理,从而导致内存泄漏。

        【讨论】:

          【解决方案6】:

          不一定,如果它正在分配静态对象(例如,实现单例模式)。

          【讨论】:

          • 从什么时候开始用new分配静态对象?
          • @FredOverflow - 当然,当它们是静态单例指针时。 ;^)
          • static MyClass *instance; 后跟if (instance==NULL) instance = new MyClass();
          【解决方案7】:

          不,不一定。您可能在其他地方存储了指向动态分配对象的指针。例如对于一些classA:

          A* ptr = NULL;
          
          void foo() {
             ptr = new A();
          }
          

          你应该在某个地方有一个delete ptr,但它不必在foo()中。

          另一方面,如果您没有将其存储在其他任何地方:

          void foo() {
             A* ptr = new A();
          }
          

          那么,是的,这是内存泄漏。你永远无法回到那个指针做delete ptr!


          请注意,最好使用一些“智能指针”实现,例如 shared_ptr 或 unique_ptr 来为您处理这些内容。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2022-01-10
            • 1970-01-01
            • 2011-12-04
            • 1970-01-01
            • 1970-01-01
            • 2010-10-15
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多