答案有几个层次。
首先,变量可以用几种不同的方式声明:
- 作为局部变量(在函数内部或作为类成员)。示例:
int i
或int i = 42
。这些具有自动存储持续时间(这些示例在技术上是auto int i
, 或的简写auto int i = 42
,尽管该auto
关键字实际上从未使用过。这意味着当这些变量超出范围时将自动释放它们。保证调用它们的析构函数(不无论你如何离开作用域,无论是通过函数返回还是抛出异常,它们的析构函数将在它们超出作用域时被调用,然后它们使用的内存被释放)。像这样声明的局部变量被分配在堆栈。
- 一个静态变量(带有
static
关键字,暗示静态存储持续时间,而不是上面显示的自动。这些只是在程序的持续时间内保留,因此不必被释放
- 在堆上,使用动态分配(
new int
或new int(42)
)。这些必须通过调用手动释放delete
。
所以在最低级别,你基本上只需要保持对称性。如果某些东西是用 分配的new
,用delete,
malloc is freed by
free , and
new[] by
delete[]` 释放它。并且没有任何这些声明的变量会自动处理,不应手动释放。
现在,为了简化内存管理,通常使用RAII 。该技术基于以下观察:只有动态分配的对象必须手动释放,并且局部变量为您提供了一个非常方便的钩子,用于在局部变量超出范围时实现自定义操作。
因此,动态分配被封装在一个单独的类中,该类可以作为堆栈上的本地对象进行分配。delete
然后,它可以在其构造函数中进行您需要的任何动态分配,并且其析构函数使用必要的调用对其进行清理。
这意味着您基本上不必调用delete
您的顶级代码。它几乎总是隐藏在 RAII 对象的析构函数后面。new
调用也变得很少,但仍然与智能指针一起使用(例如:boost::shared_ptr<int>(new int(42))
它动态分配一个整数,然后将其传递给一个智能指针,该指针接管它的所有权,并自动清理它。