Deallocating a 2D array

Started by
3 comments, last by Zekeva 17 years, 9 months ago
The following C++ code dynamically creates a 2D array of size m by n:

int** array = new int*[m];
for (int i=0;i<m;i++)
  array = new int[n];
My question is: to deallocate this array is it sufficient to go 'delete array' or do I need to go:

for (int i=0;i<m;i++)
  delete array;
delete array;
Cheers
Good, fast, cheap. Pick any two.
Advertisement
You need to do the latter. But you really shouldn't be doing it like this in C++ anyway, as there are better alternatives.

I think there's a thread going in General Programming on multidimensional array management; you might check it out.
Also, when deleting an array, you will want to use the [] notation as well:

delete [] someArray;
Deallocation must be symmetric, at run-time, to allocation. You must delete what you new, delete[] what you new[], and free() what you malloc() (although you shouldn't be doing that in C++ normally). That applies to every allocation, not just "parent" allocations. There is no reference counting magic or anything along those lines happening by default: In C++, you don't pay for what you don't ask for, but you don't get it, either.

Also, you have to make sure that for each allocation, the deallocation happens exactly once. This can be tricky business, especially if (as is very often desirable) you have multiple things pointing to the same allocation.

This is why, in C++, we try to make use of the 'Resource Acquisition Is Initialization' idiom: generally, wrap allocations into constructors and deallocations into destructors, so you can't forget the deallocation. Of course, the simplest approach there only covers the case where the object "owns" the allocated memory.

For completeness' sake, that approach looks like this:

class Foo {  Bar* myAllocation;  Foo() : myAllocation(new Bar()) {}  Foo(const Foo& other) : myAllocation(new Bar(*(other.myAllocation))) {}  Foo& operator=(const Foo& rhs) {    Foo other(rhs);    std::swap(myAllocation, other.myAllocation);    return *this;  }  ~Foo() { delete myAllocation; }}


Now when a Foo is copy-constructed, the Bar is "cloned" (note that this does not respect polymorphism, because you requested a new Bar, not a new type-of-thing-pointed-at-by-other-dot-myAllocation - sadly, C++ constructors aren't virtual, so you have to hack that kind of thing if you need it), with the pointer set to point at a newly allocated Bar which is a copy of the old one. When a Foo is default-constructed, the Bar is allocated and default-constructed. When a Foo destructs, the Bar is properly deallocated. The only complicated case is the assignment operator: when one Foo is assigned to another, what happens is that we copy-construct a temporary Foo, and then swap the pointers around so that the temporary Foo takes ownership of the current object's "old" Bar, and the current object takes ownership of the copied Bar. Finally, at the end of the function, the temporary Foo falls out of scope, so its destructor is called - deallocating the old Bar. This "copy-and-swap idiom" implicitly guards against self-assignment and also helps provide exception safety.

Anyway, in more complicated situations, we don't reinvent the wheel, but use library components. The standard library isn't much help here, but Boost provides several excellent tools, including boost::shared_ptr.

But then, the real problem here wasn't about memory management, but about creating a multi-dimensional array ;) So I will tell you again to look at Boost (in particular boost::multi_array), and also read this.
Appreciate the help everyone. The concept of a vector of pointers to vectors of T is something I considered and, whilst it's kind of complicated and messy to code, it's certainly a lot safer than a primitive array. And I'll look into the boost classes as well. Thanks again.
Good, fast, cheap. Pick any two.

This topic is closed to new replies.

Advertisement