销毁 vs 释放内存

11

在《Accelerated C++》的第11章中,作者展示了一个使用数组模拟 std::vector 行为的 Vector 类。他们使用分配器类来处理内存管理。 uncreate 函数的作用是销毁数组中的每个元素并释放为数组分配的空间:

template <class T> void Vec<T>::uncreate() {
  if (data) {

  // destroy (in reverse order) the elements that were constructed 
  iterator it = avail;
  while (it != data)
    alloc.destroy(--it);

  // return all the space that was allocated
  alloc.deallocate(data, limit - data); 
  }

  // reset pointers to indicate that the Vec is empty again 
  data = limit = avail = 0;
}

显然我们需要释放分配的空间。但我不清楚为什么我们还需要销毁每个元素。如果我们只释放内存而不销毁单个元素会发生什么?


1
如果包含的类型也为每个对象分配一些内存,该怎么办?或者是一个应该关闭的打开文件的句柄? - BoBTFish
2个回答

14
原因在于它可能会惹上麻烦。C++标准中第3.8章的第4段(对象生命周期)解释了为什么(强调我的): ``` 程序可以通过重复使用对象所占据的存储空间或显式调用具有非平凡析构函数的类类型对象的析构函数来结束任何对象的生存期。对于具有非平凡析构函数的类类型对象,在重复使用或释放该对象所占据的存储空间之前,程序无需显式调用析构函数;但是,如果没有显式调用析构函数或未使用 delete-expression(5.3.5)释放存储空间,则不应隐式调用析构函数,并且依赖于析构函数产生的副作用的任何程序均属于未定义行为。 ``` 这意味着,在占用具有平凡析构函数的对象(*)或根本没有析构函数的对象(如`ints`等)的内存上执行此操作是可以的。但是当内存包含需要在析构函数中执行某些操作(例如关闭网络连接或文件、刷新缓冲区、释放内存)的类的对象时,您将泄漏资源(并且按照标准的规定,引发未定义行为)。
(*) 如果析构函数是编译器生成的、非虚拟的,并且类成员和直接基类的析构函数均为平凡析构函数,则析构函数是平凡的。

10
销毁单个元素可以确保调用它们的析构函数,从而使它们有机会释放所拥有的任何资源。简单地释放内存不会调用放置在该内存中的对象的析构函数。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接