简体   繁体   English

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

[英]Memory Leaks in C++. Programming style

For small procedures we can prevent memory leaks in case of exception in such way: 对于小程序,我们可以通过这种方式防止内存泄漏:

proc() {

  //allocate memory for matrix
  try {
  }
  catch {
    //free matrix memory
  }
    ...

  //free matrix memory
}

In case if our procedure is more complicated: 如果我们的程序更复杂:

proc() {

  //allocate memory for matrix
  try {
  }
  catch {
    //free matrix memory
  }
    ...

  try {
  }
  catch {
    //free matrix memory
  }
    ...

  try {
  }
  catch {

    //free matrix memory
  }
    ...

  //free matrix memory
}

It looks some clumsy. 它看起来有点笨拙。 Is a better way, better programming style for memory leaks control exist? 是一种更好的方法,更好的编程风格是否存在内存泄漏控制? As far as I know, C++ has auto_ptr and we can develop procedures without any care about memory deallocation. 据我所知,C ++有auto_ptr,我们可以开发程序而不需要关心内存释放。

proc() {

  //allocate auto_ptr
  try {
  }
  catch {

  }
    ...

}

But, as far as I know, auto_ptr isn't intended even for arrays. 但是,据我所知,auto_ptr甚至不适用于数组。 So, it isn't acceptable way in general case. 因此,在一般情况下,这是不可接受的方式。

auto_ptr isn't a unique case. auto_ptr不是一个独特的案例。 It's not " auto_ptr or nothing". 这不是“ auto_ptr或没有”。 The auto_ptr is one example of a general programming idiom which handles resource allocation/deallocation without leaks. auto_ptr是一般编程习惯用法的一个例子,它处理资源分配/解除分配而没有泄漏。

That idiom is called RAII . 这个成语叫做RAII

It means that resources should be mapped to an object, which manages the resource's lifetime, and ensures that it is cleaned up at the appropriate time. 这意味着资源应该映射到一个对象,该对象管理资源的生命周期,并确保在适当的时候清理它。

In the case of auto_ptr , this is done simply by having a class store the pointer to allocated memory, and, in that class's destructor, call delete on the pointer. auto_ptr的情况下,这只需要通过让类存储指向已分配内存的指针来完成,并且在该类的析构函数中,对指针调用delete

You can do the same with your own RAII classes, using them instead of auto_ptr . 您可以使用它们而不是auto_ptr对自己的RAII类执行相同的操作。 But there are also other types of smart pointers, which are preferred over auto_ptr (which is, in fact, deprecated in C++11). 但是还有其他类型的智能指针,它们优于auto_ptr (事实上​​,在C ++ 11中已弃用)。

They are shared_ptr (a reference-counted smart pointer, which deletes the object when the last reference exists), and scoped_ptr (a safer, but limited, equivalent of auto_ptr which can be implemented in C++03), and unique_ptr , the C++11 replacement for auto_ptr , which solves the problems that auto_ptr had. 它们是shared_ptr (一个引用计数的智能指针,它在最后一个引用存在时删除对象), scoped_ptr (一个更安全但有限的,相当于auto_ptr ,它可以在C ++ 03中实现),以及unique_ptr ,C ++ 11替换auto_ptr ,它解决了auto_ptr带来的问题。 A unique_ptr can be used safely in arrays and standard containers. unique_ptr可以安全地用在数组和标准容器中。

So you shouldn't use auto_ptr , but you absolutely should use the other types of smart pointers, and RAII in general. 所以你不应该使用auto_ptr ,但你绝对应该使用其他类型的智能指针和RAII。

Don't use manual memory allocation in your client code at all! 不要在客户端代码中使用手动内存分配!

Instead, design a Matrix class that takes care of its own business. 相反,设计一个负责自己业务的Matrix类。 Then you can just say, 然后你可以说,

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

In the even of any exception anywhere, all already existing objects are destroyed, and if you designed the class right, then that would free all dynamic resources. 即使在任何地方的任何异常中,所有已经存在的对象都会被销毁,如果你设计了正确的类,那么这将释放所有动态资源。

Very very baby example of a Matrix class: 非常非常宝贝的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;
};

I was actually lazy and relegated all the actual dynamic data to a std::vector ; 我实际上是懒惰并将所有实际动态数据降级为std::vector ; no need to reinvent the wheel! 无需重新发明轮子! (Or just use a Boost.MultiArray, for that matter.) (或者只是使用Boost.MultiArray。)

There are many more smart pointers available eg from Boost , several of which have been incorporated in the new C++ standard. 还有更多可用的智能指针,例如Boost ,其中一些已经被纳入新的C ++标准。

Still, for arrays the "right choice" would be to just use STL containers, in particular std::vector if you would have used a dynamic array - on current compilers it has the same performance of a "regular" array. 尽管如此,对于数组而言,“正确选择”只是使用STL容器,特别是std::vector如果您使用动态数组 - 在当前编译器上它具有与“常规”数组相同的性能。

Keep in mind that the problem is more general than memory: every resource that must be acquired and released gives these same problems, and the C++ solution is to use smart-pointer-like classes to wrap them (acquiring ownership in the constructor, destroying the resource in the destructor); 请记住,问题比内存更通用:必须获取和释放的每个资源都会产生同样的问题,而C ++解决方案是使用类似智能指针的类来包装它们(在构造函数中获取所有权,破坏析构函数中的资源); this idiom is commonly known as RAII (Resource Acquisition Is Initialization). 这个成语通常被称为RAII (资源获取是初始化)。

Notice that in C++ code with exceptions this seems to be the only practical way to deal with the problem (since the language doesn't provide finally blocks or using statements, and every instruction is a potential return path due to exceptions). 请注意,在带有异常的C ++代码中,这似乎是处理问题的唯一实用方法(因为语言不提供finally块或using语句,并且每条指令都是由于异常而导致的潜在返回路径)。

You're right that auto pointers are not intended for arrays in the way C style pointers can be used to reference arrays. 你是对的,自动指针不是用于数组的方式,C风格的指针可以用来引用数组。 That's why there are other containers such as std::vector , std::deque , etc. You simply use std::vector<std::shared_ptr<T> > . 这就是为什么还有其他容器,如std::vectorstd::deque等。你只需使用std::vector<std::shared_ptr<T> >

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM