Lucky Man
Lucky Man

Reputation: 1518

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.

proc() {

  //allocate auto_ptr
  try {
  }
  catch {

  }
    ...

}

But, as far as I know, auto_ptr isn't intended even for arrays. So, it isn't acceptable way in general case.

Upvotes: 3

Views: 348

Answers (4)

Kerrek SB
Kerrek SB

Reputation: 477670

Don't use manual memory allocation in your client code at all!

Instead, design a Matrix class that takes care of its own business. 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:

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; no need to reinvent the wheel! (Or just use a Boost.MultiArray, for that matter.)

Upvotes: 8

Stack Overflow is garbage
Stack Overflow is garbage

Reputation: 248289

auto_ptr isn't a unique case. It's not "auto_ptr or nothing". The auto_ptr is one example of a general programming idiom which handles resource allocation/deallocation without leaks.

That idiom is called 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.

You can do the same with your own RAII classes, using them instead of auto_ptr. But there are also other types of smart pointers, which are preferred over auto_ptr (which is, in fact, deprecated in 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. A unique_ptr can be used safely in arrays and standard containers.

So you shouldn't use auto_ptr, but you absolutely should use the other types of smart pointers, and RAII in general.

Upvotes: 13

andand
andand

Reputation: 17507

You're right that auto pointers are not intended for arrays in the way C style pointers can be used to reference arrays. That's why there are other containers such as std::vector, std::deque, etc. You simply use std::vector<std::shared_ptr<T> >.

Upvotes: 1

Matteo Italia
Matteo Italia

Reputation: 126967

There are many more smart pointers available e.g. from Boost, several of which have been incorporated in the new C++ standard.

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.

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); this idiom is commonly known as RAII (Resource Acquisition Is Initialization).

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).

Upvotes: 3

Related Questions