Sign in to follow this  
CrimsonMemory

Question regarding deleting pointers to matrices

Recommended Posts

CrimsonMemory    122
Let's say I create a pointer to a matrix of doubles, as such:
double** matrix = new double*[10];
for (int i=0; i<10; i++)
    matrix[i] = new double[10];

Now, if I were planning to delete said pointer, would I just invoke the delete[] operator, like this?
delete [] matrix;

Or does delete[] not act recursively, causing me to do it this way:
for (int i = 0; i<10; ++i)
    delete [] matrix[i];

This is basically a question about how exactly delete[] operates. Thanks in advance!

Share this post


Link to post
Share on other sites
Agony    3452
It's hacky, but there's a method that simplifies both the memory layout (potentially helping the cache) as well as the cleanup, at the cost of a messy looking initialization. The idea is to allocate all the memory in one single chunk, set up pointers of the first array to point into the rest of the buffer as if it were a series of independent arrays. Here's the basic idea, minus fancies (such as templatizing the function):
double** Allocate2DArray(unsigned int width, unsigned int height)
{
char* buffer = new char[sizeof(double*) * width + sizeof(double) * width * height];
double** firstDimension = reinterpret_cast<double**>(buffer);
double* secondDimension = reinterpret_cast<double*>(buffer + sizeof(double*) * width);
double** firstDimensionEnd = firstDimension + width;
while (firstDimension < firstDimensionEnd)
{
*firstDimension = secondDimension;
firstDimension += 1;
secondDimension += height;
}

return reinterpret_cast<double**>(buffer);
}

void Deallocate2DArray(double** array)
{
//Note: I'm not sure the reinterpret_cast back into what the
//array was allocated as is necessary, but I'm doing it just to
//be safe.
delete [] reinterpret_cast<char*>(array);
}

int main()
{
double** array= Allocate2DArray(4, 3);

array[0][0] = 5.0;
array[3][2] = 7.0;
//etc.

Deallocate2DArray(array);
}


Now I'm more inclined to encourage the method that I'm pretty confident is used by Boost::MultiArray, which is to just allocate an ordinary single-dimension array, wrap it up in a class, and then do the appropriate multiplications and additions within the subscript operator's ([]) body. (Or even better, just use Boost::MultiArray itself!) However, the method above does have the benefit of requiring no multiplications, at the cost of a little bit extra memory for the first dimension array of pointers. In some cases this might be better, but I wouldn't be surprised if it wasn't. Wrapping all this up in a class also has plenty of other benefits, such as being able to store the size/shape of the multi-dimensioned array.

Share this post


Link to post
Share on other sites
CrimsonMemory    122
I had considered both of your alternatives, and, as logical and good as they are, I'm focusing on practicing low-level C++ programming with this project. I guarantee, though, were it for any other project, I would definitely opt for a more intuitive approach.

Thanks, guys!

Share this post


Link to post
Share on other sites
KulSeran    3267
I also would have to sugest something more like

class matrix
{
int width, int height
double *storage;
public:
matrix ( int w, int h } : width(w), height(h) { storage = new double[width * height]; }
~matrix ( ) { delete[] storage; }
double get ( int x, int y ) { return storage[x + y*height]; }
void set ( int x, int y, double v ) { storage[x + y*height] = v; }
double *at ( int x, int y ) { return &storage[x+y*height]; }
};

Share this post


Link to post
Share on other sites
jpetrie    13151
I would second the suggestion of a 2D interface to a 1D array, as KulSeran suggested. I would advise against the vector-of-vectors approach, because a vector-of-vectors is jagged, not rectangular.

Finally, consider boost::array or boost::multi_array. Your claims about wanting a "low level" approach make me suspicious; it sounds like you think doing things yourself in an ugly fashion would be "faster" than using an clean, sane interface, and this is most likely blatantly untrue; it's probably also destabilizing your program.

Share this post


Link to post
Share on other sites
ToohrVyk    1596
Quote:
Original post by Agony
*** Source Snippet Removed ***


Your code potentially has alignment issues. Ideally, you should use ::operator new(size) to allocate your memory, and then place the array of doubles before the array of pointers to rows.

Share this post


Link to post
Share on other sites
Bregma    9214
Quote:
Original post by CrimsonMemory
I had considered both of your alternatives, and, as logical and good as they are, I'm focusing on practicing low-level C++ programming with this project. I guarantee, though, were it for any other project, I would definitely opt for a more intuitive approach.


I would argue you're not practicing low-level C++ programming, you're practicing low-level C programming.

If you wanted to be programming in C++, you would be using std::valarray for this stuff. If you really wanted to be doing low-level C++ programming, you would be specializing std::valarray.

--smw

Share this post


Link to post
Share on other sites
linternet    344
Quote:
Original post by Bregma

I would argue you're not practicing low-level C++ programming, you're practicing low-level C programming.

If you wanted to be programming in C++, you would be using std::valarray for this stuff. If you really wanted to be doing low-level C++ programming, you would be specializing std::valarray.

--smw


and I would argue that since "new" and "delete" aren't C that his code is distinctly C++.

Share this post


Link to post
Share on other sites
ToohrVyk    1596
Quote:
Original post by linternet
and I would argue that since "new" isn't C that his code is distinctly C++.


He uses "new" instead of "malloc" and "delete" instead of "free". Hardly deserving of a distinctly epithet, if you ask me. In fact, what he wrote is C code which requires a C++ compiler to compile. Just like IOCCC entries are not representative of a sane C program.

Share this post


Link to post
Share on other sites
linternet    344
Quote:
Original post by ToohrVyk
He uses "new" instead of "malloc" and "delete" instead of "free". Hardly deserving of a distinctly epithet, if you ask me. In fact, what he wrote is C code which requires a C++ compiler to compile. Just like IOCCC entries are not representative of a sane C program.


Point taken. I just don't understand why the community constantly denigrates perfectly legal, working code simply because it doesn't adhere to the academic dogma of a language.

Share this post


Link to post
Share on other sites
ToohrVyk    1596
Quote:
Original post by linternet
Quote:
Original post by ToohrVyk
He uses "new" instead of "malloc" and "delete" instead of "free". Hardly deserving of a distinctly epithet, if you ask me. In fact, what he wrote is C code which requires a C++ compiler to compile. Just like IOCCC entries are not representative of a sane C program.


Point taken. I just don't understand why the community constantly denigrates perfectly legal, working code simply because it doesn't adhere to the academic dogma of a language.


Because it can create silly situations. Consider a 100KLOC project written in C, but C++-compilable, with a header file included almost everywhere. Add an #include <vector> at the top of that one header file. The one hundred thousand lines of C code have automagically turned into C++.

Because of this, most people use the name "C++" to refer to modern C++, to distinguish it from C-compiled-as-C++. The main idea behind this is that (modern) C++ code is more easily exception-safe, interacts better with the standard library, requires less non-default constructors and destructors, and generally requires less work than the C-like version. It is not so much academic dogma as it is using the language to its full extent, doing less work to write faster and more easily maintainable programs.

Share this post


Link to post
Share on other sites
linternet    344
Quote:
Original post by ToohrVyk
Because it can create silly situations. Consider a 100KLOC project written in C, but C++-compilable, with a header file included almost everywhere. Add an #include <vector> at the top of that one header file. The one hundred thousand lines of C code have automagically turned into C++.

Because of this, most people use the name "C++" to refer to modern C++, to distinguish it from C-compiled-as-C++. The main idea behind this is that (modern) C++ code is more easily exception-safe, interacts better with the standard library, requires less non-default constructors and destructors, and generally requires less work than the C-like version. It is not so much academic dogma as it is using the language to its full extent, doing less work to write faster and more easily maintainable programs.


Understood and well explained.

The only thing I'll mention is that when working with old code and people whose skills are out of date (me) the practical application of purley modern C++ becomes nearly impossible.

I'm about as stubborn as they come and even I've seen the benefits of using std::string, and std::vector. If however(as a stupid example) I need faster-than-linear searching and am not quite ready to use std::map, I can put c_st()'s into a 10+ year old "C-style" hash class without losing the time it would take to figure map out.

That mixing is why a language that is (to use your signature) "an octopus made by nailing extra legs onto a dog" is so popular in the first place.

Share this post


Link to post
Share on other sites
ToohrVyk    1596
Quote:
Original post by linternet
The only thing I'll mention is that when working with old code and people whose skills are out of date (me) the practical application of purley modern C++ becomes nearly impossible.


I agree. If all you know C, writing applications in modern C++ is a nigh impossible task, and a C++ compiler becomes little more than a C compiler upgrade.

Quote:
That mixing is why a language that is (to use your signature) "an octopus made by nailing extra legs onto a dog" is so popular in the first place.


Quite sadly, yes, that's true. Sadly, few people realize that they're abandoning the simplicity of C without gaining the advantages of C++. The two languages, contrary to populary belief, interact together extremely badly.

Share this post


Link to post
Share on other sites
linternet    344
Quote:

Quite sadly, yes, that's true. Sadly, few people realize that they're abandoning the simplicity of C without gaining the advantages of C++. The two languages, contrary to populary belief, interact together extremely badly.


You're basically saying that pre-standardized C++ is/was useless?

Share this post


Link to post
Share on other sites
Zahlman    1682
Quote:
Original post by linternet
Quote:

Quite sadly, yes, that's true. Sadly, few people realize that they're abandoning the simplicity of C without gaining the advantages of C++. The two languages, contrary to populary belief, interact together extremely badly.


You're basically saying that pre-standardized C++ is/was useless?


It was a prototype, in many ways.

However, there were still advantages available to be gained - in particular, constructors and destructors for classes, and language support for polymorphism - that are only gained if you seek them.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this