All,

I’m new to C++ and trying to figure out the best way to do a multidimensional array of pointers to a class.

The code I am presenting demonstrates several questions I had and am hoping to get some help with each question.

The basic idea is to create myMatrix, a two dimensional array of pointers to myClass, populate it by passing it to the function populateMatrix by reference, delete the array, and repeat these steps for a specific number of iterations (10 in the program presented).

I think the code below is 95% correct, although I get an error on line 67 that states "error C2512: 'myClass' : no appropriate default constructor available". I’m not certain how to fix this. Also, I’m not sure how to refer to the matrix once I pass it to the populateMatrix function.

Although those are my questions for the actual code, I was hoping to get some other thoughts on the coding in general. Specifically,
1) If I would like to repopulate the matrix with a different set of values each time (say, read the values from a file for example), should I create and delete the matrix for each iteration as shown, or is it more practical to simply set all the pointers to NULL and reuse it?

2) Should I be setting the pointer to NULL in line 70? I got the basic structure of the code from Wrox Professional C++ (page 360), but they don’t set the pointer to NULL. They way I read Beginning Visual C++ 2010, it seems to say all pointers should be set to null when initialized. Also, I thought I had read somewhere that pointers set to NULL don’t actually go through all the delete steps, so there is a time savings if the pointer is set to NULL to begin with and then never assigned a value. Is this true?

3) With the code shown, is all the memory in fact released between each iteration? I ask because it looks like I am cycling through the y dimension but not the x dimension. Again, the structure is from Wrox Professional C++, so I’m sure its correct, but I don’t understand exactly what happening here.

4) Also, I tried to use nullptr, but I get a C2065 error. The program is a native C++ program and I am using Visual Studio 2008. Is this available or should I stick with NULL?

Also, any other thoughts here would be greatly appreciated.

Max

// MatrixTest

#include <cstring> // For the NULL

class myClass
{
public:

	// Static int to track number of values in the matrix
	static int numberOfValuesInMatrix;

	// Constructor
	myClass( int inValue ) : value( inValue )
	{
		numberOfValuesInMatrix++;
	}

	// Destructor
	~myClass(void)
	{
	}

protected:

	int value;

};

void populateMatrix( myClass**& inMyMatrix, int inIteration, int inXDimension, int inYDimension )
{

	int populateNumber;

	for (int i = 0; i < inXDimension; i++)
	{

		for (int j = 0; j < inYDimension; j++)
		{
			// Here I want to populate inMyMatrix[i][j] with inIteration * 5000 + populateNumber,
			// but I'm not sure how I refer to inMyMatrix
			// 

			populateNumber++;
		}

	}

}

int main()
{

	const int iterations = 10;
	const int xDimension = 100;
	const int yDimension = 50;

	for (int i = 0; i < iterations; i++)
	{

		// Create and initialize myMatrix
		myClass::numberOfValuesInMatrix = 0;

		myClass** myMatrix = new myClass*[xDimension];
		for (int j = 0; j < xDimension; j++)
		{

			myMatrix[i] = new myClass[yDimension]; 	// "error C2512: 'myClass' : no appropriate default constructor available"

			// Set the pointer to NULL - is this necessary?
			myMatrix[i] = NULL;

		}

		populateMatrix( myMatrix, i, xDimension, yDimension );

		// Delete
		for (int i = 0; i < xDimension; i++)
		{
			delete[] myMatrix[i]; // Do I not have to cycle through the y dimension and delete those pointers?
		}
		delete[] myMatrix;
		myClass::numberOfValuesInMatrix = 0;

	}

	return 0;

}

I've played around with it some more and corrected a typo in line 67 and 70 to refer to j instead of i.

Also, I changed the default constructor for myClass and created a setValue method. Now I get it to compile. New code is below.

Please note, I still have several questions concerning the programming style.

Thanks,

Max

// MatrixTest

#include <cstring> // For the NULL

class myClass
{
public:

	// Static int to track number of values in the matrix
	static int numberOfValuesInMatrix;

	// Constructor
	myClass( void )
	{
	}

	// Destructor
	~myClass(void)
	{
	}

	void setValue( int inValue )
	{
		value = inValue;
	}

protected:

	int value;

};

void populateMatrix( myClass**& inMyMatrix, int inIteration, int inXDimension, int inYDimension )
{

	int populateNumber;

	for (int i = 0; i < inXDimension; i++)
	{

		for (int j = 0; j < inYDimension; j++)
		{
			// Here I want to populate inMyMatrix[i][j] with inIteration * 20 + populateNumber,
			// but I'm not sure how I refer to inMyMatrix
			// 
			populateNumber++;
		}

	}

}

int myClass::numberOfValuesInMatrix = 0;

int main()
{

	const int iterations = 10;
	const int xDimension = 4;
	const int yDimension = 5;

	for (int i = 0; i < iterations; i++)
	{

		// Create and initialize myMatrix
		myClass::numberOfValuesInMatrix = 0;

		myClass** myMatrix = new myClass*[xDimension];
		for (int j = 0; j < xDimension; j++)
		{

			myMatrix[j] = new myClass[yDimension]; 	// "error C2512: 'myClass' : no appropriate default constructor available"

			// Set the pointer to NULL - is this necessary?
			myMatrix[j] = NULL;

		}

		populateMatrix( myMatrix, i, xDimension, yDimension );

		// Delete
		for (int i = 0; i < xDimension; i++)
		{
			delete[] myMatrix[i]; // Do I not have to cycle through the y dimension and delete those pointers?
		}
		delete[] myMatrix;
		myClass::numberOfValuesInMatrix = 0;

	}

	return 0;

}

myMatrix[j] = new myClass[yDimension]; // "error C2512: 'myClass' : no appropriate default constructor available"

// Set the pointer to NULL - is this necessary?
myMatrix[j] = NULL;

You should set it to NULL before allocating memory, and after deleting the memory. No that's not necessary there.


you could define nullptr yourself--or switch to Visual Studio 2010, which supports "nullptr", "auto", lamba functions, new random number generation facilities, rvalue references, and maybe more.

auto f = []() { std::cout << "Hello C++0x TR1" << std::endl; };
f();

College students can get Visual Studio 2010 Professional for free at: www.dreamspark.com

pseudorandom21,

Thanks for the response.

I use VS 2010 on my personal computer, but right now I am working on a government computer and our admin guy says VS 2010 isn't approved yet for some reason. I wanted to verify nullptr wassn't available until VS 2010 since I saw somewhere (where?) that it was part of VS 2005.

Max

int populateNumber;

should always be (imo) : int populateNumber = 0; Try this on for size:

int main()
{

	const int iterations = 10;
	const int xDimension = 4;
	const int yDimension = 5;

	for (int i = 0; i < iterations; i++)
	{

		// Create and initialize myMatrix
		myClass::numberOfValuesInMatrix = 0;

		myClass **myMatrix = nullptr;//<-- I tend to use myClass *myMatrix[]
		myMatrix = new (myClass*[xDimension]);//Array of pointers (which point to pointers)
		//as of now there are xDimension # of pointers (which point to pointers) in "myMatrix".

		for(int m = 0; m < xDimension; m++){
			myMatrix[m] = nullptr;
			myMatrix[m] = new myClass[yDimension]();//<-- special attention here.
			//Now you have an array of pointers that point to "arrays" of myClass's.
			//or if it's easier to think about, an array of pointers that point to other pointers (which are pointing to arrays).
		}

		populateMatrix( myMatrix, i, xDimension, yDimension );

		// Delete
		for (int i = 0; i < xDimension; i++)
		{
			delete[] myMatrix[i]; // Do I not have to cycle through the y dimension and delete those pointers?
		}
		delete []myMatrix;//<-- deleting other dimension.
		//depending on how you think about it, x and y can become quite confusing.  But no, you are deleting it all.

		myClass::numberOfValuesInMatrix = 0;

	}

	return 0;

}

If I'm not mistaken, you were trying to create an array of pointers to pointers, then the pointers to pointers in turn point to arrays of myClass's.

It's kind of like making a vector of vectors:

vector< vector<int> > myMatrix;
vector<int> x_val(20,0);
myMatrix.push_back(x_val);

int y_value = 100;
myMatrix.at(0).push_back(y_value);

Although I really don't know why you're doing that in a loop.

Pseudorandom21,

Thanks again for the reply.

For this example, what I am shooting for is a 4x5 matrix of pointers on the stack pointing to myClasses on the heap.

In my first example, where I essentially had:

for (int m = 0; m < xDimension; m++)
		{
			myMatrix[m] = new myClass[yDimension]();
			myMatrix[m] = NULL;
		}

was I just deleting the pointer right after I created it?

My actual application will have 200 x 20,000 pointers on the stack pointing to 4,000,000 classes on the heap (actually, I am hoping this forum can tell me if that’s what I need to do). For the most part not even a fraction of those classes are necessary. About 120 x 1,000 is the array size for about 95% of what I need, but I would like to have the larger matrix available for the 5% of the time that I do need it. When I write the program to just create the matrix and then delete the matrix, it takes a while to delete it unless I set the pointers to null *after* the new statement, but I don't fully know why. The NULL statement before the new statement makes the time between the iterations excessively long, but it is relatively quick if I set it after the new statement. But again, I may be messing something up since I don't fully understand what is happening with the pointer.

What’s your thoughts on repopulating the matrix rather than deleting and recreating it for each iteration? I would think I would have to go through the entire matrix again and set all the pointers to NULL. Would this work and would it be quicker than deleting/recreating?

Also, do you have any advice on how I refer to the matrix once it is passed to the populateMatrix function?

Thanks again for your response.

Max

PS

int populateNumber = 0;

D’oh!

When I write the program to just create the matrix and then delete the matrix, it takes a while to delete it unless I set the pointers to null *after* the new statement, but I don't fully know why.

You have to make sure that you don't lose a pointer to an object you allocated with "new", otherwise it will be impossible to delete it (free the memory) and you will have a memory leak.

My guess is that the compiler optimizes the allocation/memory leak sequence so that it doesn't even allocate any memory--because it would be impossible to use the allocated memory anyway.

Typically one would want to use this sequence:

//Create a pointer set to NULL/nullptr
long *lp = NULL;
//Allocate memory with "new", which means the pointer now equals the
//address of the newly allocated memory.
lp = new long;
//...Use the variable/class instance.
//

//Delete the allocated memory, and set to NULL/nullptr.
delete lp;
lp = NULL;

Unfortunately what we've done doesn't allocate your pointers on the stack, I really don't see how we could. C++ doesn't take too kindly to dynamically allocating stuff on the stack. There are compilers that allow that, however.

Also, I updated the delete portion to:

// Delete
		for (int i = 0; i < xDimension; i++)
		{
			delete[] myMatrix[i];
			myMatrix[i] = NULL;
		}
		delete[] myMatrix;
		myMatrix = NULL;
		myClass::numberOfValuesInMatrix = 0;

based on your comment to set the pointers to NULL after deleting the memory.

My full code is now:

// MatrixTest

#include <cstring> // For the NULL

class myClass
{
public:

	// Static int to track number of values in the matrix
	static int numberOfValuesInMatrix;

	// Constructor
	myClass( void )
	{
	}

	// Destructor
	~myClass(void)
	{
	}

	void setValue( int inValue )
	{
		value = inValue;
	}

protected:

	int value;

};

void populateMatrix( myClass**& inMyMatrix, int inIteration, int inXDimension, int inYDimension )
{

	int populateNumber = 0;

	for (int i = 0; i < inXDimension; i++)
	{

		for (int j = 0; j < inYDimension; j++)
		{
			// Here I want to populate inMyMatrix[i][j] with inIteration * 20 + populateNumber,
			// but I'm not sure how I refer to inMyMatrix
			//
			populateNumber++;
		}

	}

}

int myClass::numberOfValuesInMatrix = 0;

int main()
{

	const int iterations = 10;
	const int xDimension = 4;
	const int yDimension = 5;

	for (int i = 0; i < iterations; i++)
	{

		// Create and initialize myMatrix
		myClass::numberOfValuesInMatrix = 0;

		myClass** myMatrix;
		myMatrix = new (myClass*[xDimension]);

		for (int m = 0; m < xDimension; m++)
		{
			myMatrix[m] = NULL;
			myMatrix[m] = new myClass[yDimension]();
		}

		populateMatrix( myMatrix, i, xDimension, yDimension );

		// Delete
		for (int i = 0; i < xDimension; i++)
		{
			delete[] myMatrix[i];
			myMatrix[i] = NULL;
		}
		delete[] myMatrix;
		myMatrix = NULL;
		myClass::numberOfValuesInMatrix = 0;

	}

	return 0;

}

Sorry, you're right -- the entire matrix of pointers is on the heap because I used "new" to allocate the memory. I've used Pascal before, but I'm new to C++ and the memory tracking with pointers, so I get easily lost.

On the heap is fine also (actually preferable I think) -- right?

Actually NULL is in the <cstddef> header--C standard defines.

and on my previous example I forgot to intialize the pointer to NULL, so: myClass** myMatrix = NULL; Otherwise it's pretty perfect, and won't leak memory. Congrats.

I did forget to ask why you're passing the pointer-to-pointer by reference, do you intend to modify the actual pointer? That would be a massively bad idea that would lead to leaking more memory.

Nothing is copied when you pass a pointer to some data by value except the pointer--which is probably ideal unless you want to use a const reference.

--edit-- only one pointer is copied.

Here is the syntax: void populateMatrix( myClass ** const & inMyMatrix, int inIteration, int inXDimension, int inYDimension ) That is a const reference to a pointer-to-pointer, it doesn't allow the person to modify the actual pointer (the only copy you have) that points to all your data.

There are two ways to use const, one is for constant data, the second is for constant pointers. Here I have used a constant pointer so that no one uses pointer arithmetic and destroys the only pointer you have to all that allocated memory.

Hope it all works out now.

OK, I'm updating the code now based on this discussion and passing just the pointer to the function, which now allows me to reference the matrix with the much easier standard

inMyMatrix[i][j].setValue(inInteration * 20 + populateNumber);

One more question - should I try to create the matrix only once at the start of the program and then delete at the end while resetting the pointers back to NULL at the start of each iteration?

Can I even do this?

One more question - should I try to create the matrix only once at the start of the program and then delete at the end while resetting the pointers back to NULL at the start of each iteration?

If you set a pointer which is pointing to something to NULL before you delete it, that is a memory leak. You may do so after deleting it, however.

Please review the process I have posted on one of my earlier posts, and I have updated my previous post with information about the const pointer to data. Though there is really only one pointer being copied, and it's a pointer-to-a-pointer.

Here is a revision to your function:

void populateMatrix( myClass ** const & inMyMatrix, int inIteration, int inXDimension, int inYDimension )
{

	int populateNumber = 0;

	for (int i = 0; i < inXDimension; i++)
	{

		for (int j = 0; j < inYDimension; j++)
		{
			// Here I want to populate inMyMatrix[i][j] with inIteration * 20 + populateNumber,
			// but I'm not sure how I refer to inMyMatrix
			//
			populateNumber++;
			inMyMatrix[i][j].setValue(inIteration * 20 + populateNumber);
			//I'm so tired of this...
			//Ok, so the order of operations for programming in C/C++ dictates
			//that the inIteration * 20 will be evaluated BEFORE adding populateNumber.
			//Is this the desired effect?
		}

	}

}

pseudorandom21,

Thanks again for the help.

Just one more question - is there a way to create and delete the matrix only once for the entire program rather than at the start of each iteration?

It's not a big deal for this 4 x 5 matrix, but I think it would be better to do just once for the real world 200 x 20,000 matrix.

Thoughts?

EDIT -- Sorry, it looked to me like my previous post with this question was inadvetantly deleted, so I reposted.

Thanks again for all the help!

For future reference, completed code w/ help from pseudorandom21:

// MatrixTest

#include <cstddef>

class myClass
{
public:
	// Static int to track number of values in the matrix
	static int numberOfValuesInMatrix;

	// Constructor
	myClass( void )
	{
	}

	// Destructor
	~myClass(void)
	{
	}

	void setValue( int inValue )
	{
		value = inValue;
	}

protected:

	int value;

};

void populateMatrix( myClass** const & inMyMatrix, int inIteration, int inXDimension, int inYDimension )
{

	int populateNumber = 0;

	for (int i = 0; i < inXDimension; i++)
	{
		for (int j = 0; j < inYDimension; j++)
		{
			inMyMatrix[i][j].setValue( ( inIteration * 20 ) + populateNumber );
			populateNumber++;
		}
	}

}

int myClass::numberOfValuesInMatrix = 0;

int main()
{

	const int iterations = 10;
	const int xDimension = 4;
	const int yDimension = 5;

	// Iterate
	for (int i = 0; i < iterations; i++)
	{

		// Create myMatrix
		myClass** myMatrix = NULL;
		myMatrix = new (myClass*[xDimension]);
		for (int m = 0; m < xDimension; m++)
		{
			myMatrix[m] = NULL;
			myMatrix[m] = new myClass[yDimension]();
		}

		myClass::numberOfValuesInMatrix = 0;

		populateMatrix( myMatrix, i, xDimension, yDimension );

		// Delete myMatrix
		for (int i = 0; i < xDimension; i++)
		{
			delete[] myMatrix[i];
			myMatrix[i] = NULL;
		}
		delete[] myMatrix;
		myMatrix = NULL;
		myClass::numberOfValuesInMatrix = 0;

	}

	return 0;

}

Marked as solved.

I would suggest RAII -- resource acquisition is initialization.
http://en.wikipedia.org/wiki/Resource_Acquisition_Is_Initialization

In which, you create a class that will manage your resource acquisition (allocating your matrix on the heap), and when it goes out of scope it's deleted safely, even if exceptions occur.

An example of my idea:

#include <iostream>
class MemoryManager
{
  char *chunk;
  //Constructor
  MemoryManager() : chunk(NULL)
  {
    chunk = new char[4086];//<-- allocate.
  }
  //Destructor
  ~MemoryManager()
  {
    delete [] chunk;
  }
};

int main()
{
  MemoryManager m;
  std::cout << "Memory is allocated; press ENTER." << std::endl;
  std::cin.get();
  return 0;//<-- memory is de-allocated at program end.
}

I haven't tested it, but it's so trivial I don't expect any bugs.

It works because the class that allocated all the memory is on the stack, and when it goes out of scope the destructor deletes the heap allocated memory.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.