C ++中的内存泄漏。编程风格

时间:2012-01-15 23:10:08

标签: c++ memory-leaks

对于小程序,我们可以通过这种方式防止内存泄漏:

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甚至不适用于数组。因此,在一般情况下,这是不可接受的方式。

4 个答案:

答案 0 :(得分:13)

auto_ptr不是一个独特的案例。这不是“auto_ptr或没有”。 auto_ptr是一般编程习惯用法的一个例子,它处理资源分配/解除分配而没有泄漏。

这个习语称为RAII

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

auto_ptr的情况下,这只需要通过让类存储指向已分配内存的指针来完成,并且在该类的析构函数中,在指针上调用delete

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

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

所以你不应该使用{{1}},但你绝对应该使用其他类型的智能指针和RAII。

答案 1 :(得分:8)

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

相反,设计一个负责自己业务的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。)

答案 2 :(得分:3)

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

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

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

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

答案 3 :(得分:1)

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