对析构函数怀疑

时间:2012-05-03 14:58:14

标签: c++

假设我有一个班级:

class ClassX{
   private:
      int* p;
      int i;
   ....
}

我在某处:

ClassX x;
.....
//and in a friend function or in a ClassX function
p = (int*) malloc (.....);

然后当x退出其范围时,调用析构函数;但它没有释放malloc权限分配的内存吗?

如果我重新定义它:

ClassX::~ClassX(){ delete [] p; }

它释放了malloc分配的内存,但没有释放为类字段分配的内存(即ip)?

我错过了什么吗?

谢谢。

6 个答案:

答案 0 :(得分:3)

简单的规则是:对于每个malloc,必须只有一个free;对于每个new,必须只有一个delete;对于每个new[],必须只有一个delete[]

回答你的问题:

  

[析构函数]没有释放malloc分配的内存吗?

正确。它不是。在这种情况下,您调用了malloc,但从未调用free

  

[修改后的析构函数]释放malloc分配的内存,但不释放为类字段分配的内存?

错误。它不释放内存(在这种情况下,您必须使用free,而不是delete[]freemalloc的合作伙伴。delete[]是{{1}合作伙伴。你无法切换合作伙伴。)

同样错误的是,它释放了为类的字段分配的内存(假设字段是非指针类型。)在析构函数返回后,释放对象占用的内存

  

我错过了什么吗?

如果您要使用原始指针,还需要了解Rule of Three。但是,更好的是,永远不要使用原始指针。使用smart pointercontainer

答案 1 :(得分:3)

首先,请记住以下事项:

  1. malloc分配的内容需要free
  2. 取消分配
  3. 请勿使用malloc
  4. new分配的内容必须由delete
  5. 取消分配
  6. new[]分配的内容必须由delete[]
  7. 取消分配
  8. 每个delete一个new,每个delete[]一个new[]
  9. 请勿使用以上任何一种
  10. 然后,您认为没有析构函数,malloc分配的内存将不会被释放,这是正确的。如果您遵循上述规则,则需要使用freedelete[] )来解除分配:

    ClassX::~ClassX() { free(p); }
    

    但是,您首先不应该在C ++中使用malloc,因为它不会调用对象的构造函数,您应该使用new

    ClassX::ClassX() : p(new int) { }
    
    // NOW we use delete since we used new (not delete[] since we didn't use new[])
    ClassX::~ClassX() { delete p; }
    

    但是,如果这样做,则必须编写复制构造函数,复制赋值运算符,移动构造函数和移动赋值运算符。那么让我们看一个更好的方法:

    class ClassX{
    private:
        ClassX();
    
        std::unique_ptr<int> p;
        int i;
        ....
    };
    
    // we have to break rule #6 here
    ClassX::ClassX() : p(new int) { }
    

    现在你甚至不必写一个析构函数,你可以让智能指针为你处理它,因为它会自动调用你delete所做的事情的new。析构函数被称为。这导致我们......

    你的另一个问题:

      

    它释放了malloc分配的内存,但没有释放为类'字段分配的内存(即i和p)?

    这大约是正确的1/4。由于ip是该类的成员,因此在取消分配封闭类时会自动释放它们,如果它们是类本身,他们的析构函数将被称为。因此,如果你将delete放在你的析构函数中,它会处理new分配的内存,ip会自动清理,一切都很好。 (你只有1/4正确,因为你使用了错误的释放函数。)

    这意味着,如果您使用智能指针,则在您的对象被销毁时将调用智能指针的析构函数,并且它将自动释放您为new分配的内容。所以你甚至不用担心它。

    这是假设您真的希望将动态int作为您班级的一部分。但是,如果你可以,你宁愿存储int的值(不存储它的指针),这样你就不必乱用智能指针,释放或任何其他东西。

答案 2 :(得分:1)

如果你手动分配内存,你必须释放它,它不会自动为你释放。

如果您致电malloc(或callocrealloc),则需要free该内存。同样,如果您new某事deletenew[]必须与delete[]匹配。

话虽这么说,你是用C ++编程的,并且很少有理由手动管理内存。使用智能指针,std::shared_ptr用于共享所有权,std::unique_ptr用于其他方式。

然后你的班级看起来像这样:

#include <memory>

class ClassX{
   private:
      std::unique_ptr<int> p;
      int i;
      ....
};

ClassX::ClassX() : p( new int ) {} /* No need to deallocate p manually */

请注意,unique_ptr对数组也有部分特化,所以如果p指向数组,则可以按如下方式分配内存:

class ClassX{
   private:
      std::unique_ptr<int[]> p;
      int i;
      ....
};

Class::ClassX() : p ( new int[10] ) {}

您也可以完全忘记处理指针并使用std::vectorstd::array,尤其是对于像int数组这样简单的事情。

答案 3 :(得分:1)

你的析构函数应该释放p是正确的,但如果你用malloc分配,你应该用free释放内存。或者你可以用以下内容分配内存:

x.p = new int[size];

这意味着你的delete[] p;析构函数是正确的。

关于类的成员变量,您不必担心删除它们,如果您的对象是在堆栈上分配的,它们将在堆栈展开时被删除。如果您的类已在堆上分配,则在delete x;时将删除它们。无论哪种方式,它们的生命周期都与包含它们的对象相关联。

答案 4 :(得分:1)

为了简化,我总是告诉自己指针只是一个整数。 (根据系统的不同,它可以是16,32或64位长)。它是一个特殊的整数,有助于定义一个地址,但它只是一个整数

因此,当您构造类X时,它会为两个“整数”分配空间。一个叫做p,另一个叫做i。当类被破坏时,它会释放两个整数和一些东西的空间。

析构函数不会打扰您使用特殊整数p(表示地址)的值。您可以像创建内存一样创建内存,或者创建一个随机数:它在表示类X的内存中完全相同:只是一个整数。

答案 5 :(得分:1)

规则很简单:

  • 分配有new的内存应使用delete释放。
  • 分配有new []的内存应使用delete []释放。
  • 分配有malloc()的内存应使用free()释放。

请注意,您需要将分配函数返回的完全相同的地址传递给解除分配函数。

良好做法:

  • 除非您确实需要动态分配,否则最好避免动态分配。
  • 如果必须,您应该使用某种适合您要求的智能指针,决定使用哪个智能指针取决于所涉及的所有权和生命周期语义。
  • 在C ++中,很少有人需要使用mallocfree,除非你有充分的理由,否则不要使用它们,

此外,在您的情况下,您还需要关注 Rule of Three ,以便您的程序正常运行。