Reputation: 1518
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
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
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
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
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