【问题标题】:Heap and delete in function calls. How do I delete local dynamic memory?函数调用中的堆和删除。如何删除本地动态内存?
【发布时间】:2013-11-11 18:19:50
【问题描述】:

我知道已经动态分配并使用堆的内存需要使用 delete 手动删除。如果在超出范围的类函数中创建动态对象也是这种情况吗?这是一个sn-p。

    Fraction* Fraction::add(const Fraction* fr) const{ 
      int gcd;
      Fraction* temp;

      gcd = gcdRecur(num * fr->denom + fr->num * denom, 
                     denom * fr->denom);

      temp = new Fraction((num * fr->denom + fr->num * denom) / gcd, 
                          (denom * fr->denom) / gcd);

      return temp;
   }

在这种情况下, temp 是指向使用“new”的 Fraction 类型的动态对象的指针(对吗?)。如果我将此指针返回到调用类函数“add”的位置,是否需要删除本地指针“temp”?如果是这样,我该如何做到这一点?

编辑:我对在此类成员中使用 new 的(错误)解释是因为 Fraction 对象是通过指向 Fractions 的指针实例化的(像这样):

    int main() {
      menu()
      return 0;
    }

    void menu() {
      Fraction* fr1 = 0;
      Fraction* fr2 = 0;
      Fraction* fr3 = 0;
      // ... user chooses to initialize, so fr1, fr2, fr3 no longer null

      // ... user chooses to add. call submenu, pass fr1, fr2, fr3 by POINTERS?
      addMenu(fr1, fr2, &fr3);
    }

看起来很糟糕...这是 addMenu 的标题:

     void addMenu(const FractionTeddyD*, const FractionTeddyD*, FractionTeddyD**);

编辑#2:在不使用“新”的情况下解决。 T

【问题讨论】:

    标签: c++ dynamic return member delete-operator


    【解决方案1】:

    确实需要删除,否则内存会泄露。你不能在本地删除它,因为调用者需要在函数返回后使用它。一旦不再需要,调用者将不得不将其删除。显然,这很容易出错,这就是为什么您应该始终使用RAII 来管理动态资源。

    在这种情况下,您应该将返回类型更改为智能指针,例如std::unique_ptr<Fraction>

    另一方面,你为什么在这里使用new?返回值会更简单,而且几乎可以肯定更快。

    【讨论】:

    • 我需要在已设置为 Null 的独立“菜单”函数中创建指向 Fraction 对象的指针,直到用户选择初始化 Fraction 对象。当用户想要对已初始化的分数进行加/减/乘时,必须从使用独立/成员/成员操作符函数的选项中调用附加子菜单。我想我在将这些指针传递给子菜单时遇到了麻烦(我像这样传递它们:...(const Fraction* ...)。这可能就是我一开始就遇到麻烦的原因。
    • 在这种情况下,我认为我不能按值返回,除非我在子菜单中创建本地对象,然后将这些值分配给我通过的 Fraction 指针......这是比我现在的好?此外,出于此分配的目的,我不能使用智能指针。
    【解决方案2】:

    您可以使用智能指针,例如std::unique_ptrstd::shared_ptr

     std::unique_ptr<Fraction> Fraction::add(...) const { 
    
          ...
    
          std::unique_ptr<Fraction> temp (new Fraction(...));
    
          return temp;
      }
    

    而且你可以不用担心删除内存。

    【讨论】:

      【解决方案3】:

      您需要在停止使用内存后立即删除它。内存不会为你释放,除非你的编译器有内置的内存清理系统,并且嵌入到你的*.exe文件中。

      附带说明:您可能不想在add 函数中分配新内存。尝试阅读overloading operators。当您查找该术语时,您可能会注意到operator + 通常返回对类实例的引用。而且我认为这可能是解决您问题的更好解决方案。

      如果您确实需要指针,并且不想为何时删除它而烦恼,有许多类存储智能指针,例如std::shared_ptr (reference)

      【讨论】:

        【解决方案4】:

        c++ 中的指针是按值传递的,这意味着您可以在任何有指针的地方删除对象(只要它尚未被删除)。因为它们本质上只是存储一个地址,这很好,因为当调用 delete 时,它​​知道在哪里以及如何释放内存。

        在你的情况下,你会在函数之外删除它,否则返回它是没有意义的。为了避免自己管理内存,您实际上应该使用std::unique_ptr

        std::unique_ptr<Fraction> Fraction::add(const Fraction* fr) const{ 
          int gcd;
        
          gcd = gcdRecur(num * fr->denom + fr->num * denom, 
                         denom * fr->denom);
        
          std::unique_ptr<Fraction> ptr(new Fraction((num * fr->denom + fr->num * denom) / gcd, 
                              (denom * fr->denom) / gcd));
        
          return ptr;
        

        }

        使用这种风格会省去很多麻烦,现在在 c++ 中被认为是惯用的。参数fr 也可以作为unique_ptr 传递,要采用这种编码风格,您还需要了解std::shared_ptr,它表示一个没有唯一所有权的ptr(可以存在多个)。

        然而真正的问题是当你在堆上创建一个对象而不用对象的地址保存指针时。然后该对象丢失并且无法释放。

        【讨论】:

          【解决方案5】:

          你对可能的小类分数的设计可能不好。

          拥有:

          class Fraction {
              public:
              int numerator;
              int denominator;
          };
          

          你可以通过引用传递并通过值返回:

          Fraction Fraction::add(const Fraction& fr) const;
          

          【讨论】:

          • 只是在玩简单的代码!但是,如果我主要创建指向我将创建的对象的 Fraction 指针(因为我有一个菜单,并且我不希望在用户选择这样做之前初始化 Fraction 对象),我仍然可以传递一个对指针的引用(像这样?:const Fraction*& fr)并将 Fraction Fraction::add(const Fraction& fr) const 的返回类型;还有效吗?
          • 为什么没有无效分数的向量{0, 0} 或分数图?
          • 这个作业不能使用矢量或地图! (不幸)
          猜你喜欢
          • 1970-01-01
          • 2016-05-23
          • 1970-01-01
          • 1970-01-01
          • 2018-03-29
          • 2011-06-17
          • 2013-12-27
          • 2012-06-29
          • 2018-01-25
          相关资源
          最近更新 更多