1

假设我有一堂课:

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)分配的内存?

我错过了什么吗?

谢谢你。

4

6 回答 6

3

首先,记住以下几点:

  1. 分配的东西malloc需要释放free
  2. 不要使用malloc
  3. 分配的东西new必须由delete
  4. 分配的东西new[]必须由delete[]
  5. 一份delete一份,new一份一份delete[]new[]
  6. 不要使用上述任何一种

那么,你的想法是正确的,没有析构函数,分配的内存malloc将不会被释放。如果您遵循上述规则,那么您需要使用free( notdelete[] ) 来释放它:

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

但是,您首先不应该malloc在 C++ 中使用,因为它不调用对象的构造函数,您应该使用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析构函数,它会处理由 分配的内存newi并且p会自动清理,一切都很好。(你只正确了 1/4,因为你使用了错误的释放函数。)

这意味着,如果你使用智能指针,当你的对象被破坏时,智能指针的析构函数会被调用,它会自动释放你分配new给你的东西。所以你甚至不需要担心它。

这一切都假设你真的想在你的课程中加入动态int。如果可以的话,您更愿意存储int按值(而不是存储指向它的指针),这样您就不必弄乱智能指针、释放或任何其他东西。

于 2012-05-03T15:06:34.187 回答
3

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

要回答您的问题:

[析构函数] 不会释放 malloc 分配的内存吧?

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

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

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

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

我错过了什么吗?

如果你打算使用原始指针,你还需要了解三法则。但是,更好的是,永远不要使用原始指针。使用智能指针容器

于 2012-05-03T15:02:46.777 回答
1

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

如果你调用malloc(or calloc, or realloc) 你需要free那个记忆。同样,如果你new的东西delete它,并且new[]必须被匹配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::vectoror std::array,尤其是对于像整数数组这样简单的东西。

于 2012-05-03T15:04:08.337 回答
1

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

x.p = new int[size];

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

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

于 2012-05-03T15:05:04.453 回答
1

为了简单起见,我总是告诉自己一个指针只是一个整数。(取决于系统,它可以是 16、32 或 64 位长)。它是一个特殊的整数,有助于定义地址,但它只是一个整数

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

析构函数不会打扰您对特殊整数 p (表示地址)的值所做的事情。您可以像以前那样创建内存,或者创建一个随机数:在表示 X 类的内存中都是一样的:只是一个整数。

于 2012-05-03T15:06:20.183 回答
1

规则很简单:

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

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

良好做法:

  • 除非您真的需要动态分配,否则避免动态分配始终是一个好习惯。
  • 如果必须,您应该使用某种适合您要求的智能指针,使用哪个智能指针的决定取决于所有权和所涉及的生命周期语义。
  • 在 C++ 中,很少有人需要使用malloc并且free不使用它们,除非你有充分的理由这样做,

此外,在您的情况下,您还需要遵循三法则才能使您的程序正常工作。

于 2012-05-03T15:06:31.970 回答