内存泄漏C++.编程风格

Memory Leaks in C++. Programming style

本文关键字:风格 编程 C++ 泄漏 内存      更新时间:2023-10-16

对于小过程,我们可以通过以下方式防止异常情况下的内存泄漏:

proc() {
  //allocate memory for matrix
  try {
  }
  catch {
    //free matrix memory
  }
    ...
  //free matrix memory
}

如果我们的程序更复杂:

proc() {
  //allocate memory for matrix
  try {
  }
  catch {
    //free matrix memory
  }
    ...
  try {
  }
  catch {
    //free matrix memory
  }
    ...
  try {
  }
  catch {
    //free matrix memory
  }
    ...
  //free matrix memory
}

它看起来有些笨拙。是否存在更好的方法,更好的内存泄漏控制编程风格?据我所知,C++已经auto_ptr,我们可以开发程序而不关心内存释放。

proc() {
  //allocate auto_ptr
  try {
  }
  catch {
  }
    ...
}

但是,据我所知,auto_ptr甚至不适用于数组。因此,在一般情况下,这是不可接受的方式。

auto_ptr并不是

一个独特的情况。这不是"auto_ptr或什么都没有"。auto_ptr是一般编程习惯用法的一个例子,它处理资源分配/释放而不会泄漏。

这个成语叫做RAII。

这意味着资源应映射到一个对象,该对象管理资源的生存期,并确保在适当的时间清理资源。

auto_ptr的情况下,只需让一个类存储指向已分配内存的指针,并在该类的析构函数中调用指针上的delete即可。

您可以对自己的 RAII 类执行相同的操作,使用它们而不是 auto_ptr 。但也有其他类型的智能指针,它们优先于auto_ptr(实际上,在 C++11 中已弃用(。

它们是shared_ptr(引用计数的智能指针,当最后一个引用存在时删除对象(和scoped_ptr(更安全但有限的等价物,可以在C++03中实现auto_ptr(,以及unique_ptr,C++11替代auto_ptr,解决了auto_ptr遇到的问题。unique_ptr可以安全地用于阵列和标准容器。

所以你不应该使用auto_ptr,但你绝对应该使用其他类型的智能指针,以及一般的RAII。

不要在客户端代码中使用手动内存分配!

相反,设计一个负责自己业务的Matrix类。然后你可以说,

void proc()
{
    Matrix m1;  // might throw
    // ...
    Matrix m2;  // might also throw
    // ...
}

在任何地方的任何异常中,所有已经存在的对象都会被销毁,如果你设计了正确的类,那么这将释放所有动态资源。

非常非常婴儿的Matrix类示例:

struct Matrix
{
    Matrix(size_t m, size_t n) : buf(m * n), M(m), N(n) { }
    int & operator(size_t i, size_t j) { return buf[i * N + j]; }
private:
    std::vector<int> buf;
    size_t M;
    size_t N;
};

我其实很懒,把所有实际的动态数据都放到一个std::vector;不需要重新发明轮子!(或者只是使用Boost.MultiArray

还有更多可用的智能指针,例如来自 Boost,其中一些已被纳入新的 C++ 标准。

尽管如此,对于数组,"正确的选择"是只使用 STL 容器,特别是std::vector如果您使用动态数组 - 在当前编译器上,它具有与"常规"数组相同的性能。

请记住,这个问题比内存更普遍:必须获取和释放的每个资源都会产生相同的问题,C++解决方案是使用类似智能指针的类来包装它们(在构造函数中获取所有权,在析构函数中销毁资源(;这个成语通常被称为RAII(资源获取是初始化(。

请注意,在C++有异常的代码中,这似乎是处理问题的唯一实用方法(因为该语言不提供finally块或using语句,并且由于异常,每条指令都是潜在的返回路径(。

你是对的,自动指针不适用于数组,就像 C 样式指针可用于引用数组一样。 这就是为什么还有其他容器,例如std::vectorstd::deque等。 您只需使用std::vector<std::shared_ptr<T> >.