Declaring A Variable Length Array Within A Class

Jul 27, 2011 at 8:07pm
I've been digging around and I'm having trouble figuring this one out on my own. In my program I have a class that contains a 2 dimensional array and some information and routines regarding the array. I'd like to declare the array as a variable length array (i.e. myArray[xDim][yDim] rather than myArray[12][12]) so that I may have the dimensions as a parameter at the beginning of my program. It doesn't need to be dynamic since it won't change throughout the program, but I have no trouble with this sort of thing outside of classes. I just make the variable a const int and it's all good (i.e. const int xDim = 12; myArray[xDim][xDim]). Declaring a member variable of my class const means I can't set it through a constructor, so my usual method won't work here. I did get this to work:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include <iostream>
using namespace std;

class block
{
public:
	block(int);
	~block();
	int length;
	float *data;
}; //end block

block::block(int a)
{
	length = a;
	data = new float[length];
} //end block::block

block::~block()
{
	delete [] data;
} //end block::~block


int main(int argc, char **args)
{
	int length = 12;
	block hmod(length); //hmod now contains an array of length 12
	
	return 0;
} //end main 

But this has the unfortunate effect of losing out of bounds checking. If someone tried to access hmod.data[12] they'll get garbage instead of a seg fault. I have qualms with #define (has to be implementation header file) and declaring a global (globals are icky).

Is there another way to set the size with the constructor? Something along the lines of:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <iostream>
using namespace std;


class block
{
public:
	block(int);
	const int length;
	float data[length];
}; //end block

block::block(int a)
{
	length = a;
} //end block::block


int main(int argc,char **args)
{
	int length = 12;
	block hmod(length);
	
	return 0;
} //end main 
Jul 27, 2011 at 8:19pm
Create your own bounds checking with operator[]().
Jul 27, 2011 at 8:28pm
Do you mean overload the [ ] operator to do bounds checking on pointers? How would I go about that exactly? I'm not sure where I would check to get the length since it would be different for different instantiations of the class.
Jul 27, 2011 at 9:30pm
closed account (zb0S216C)
What you'd do is create a new data member that keeps track of the current amount of elements within the allocated array. Using this data member, you can perform index validation checks. For example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class block
{
    ...
    unsigned int TotalElements;
    int *data; // Allocated elsewhere.

    int *operator [ ] ( const unsigned int Index )
    {
        if( ( Index >= 0 ) && ( Index <= ( TotalElements - 1 ) ) )
            return &data[ Index ];
   
        else return nullptr;
    }
};

Wazzak
Jul 27, 2011 at 10:21pm
I would have thought it should be

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class block
{
    ...
    unsigned int TotalElements;
    int *data; // Allocated elsewhere.

    int& operator [ ] ( unsigned int Index )
    {
        static int s_invalidElem = 0;

        if( Index <  TotalElements )
            return data[ Index ];
        }

        return s_invalidElem;
};


Notes
- There no need for 0 <= test as the index is unsigned
- <= x - 1 is the same as < x
- no need for const when passing param by value
- I would probably define a const version of method as well
- You could stick an assert in for the debug build
Jul 28, 2011 at 4:42am
Thanks, that helps somewhat, but I'm looking for another approach to passing in a constant for the dimension of the member array if there is one. I've been playing around with this pointer/new method some more and noticed a couple more limitations (if not with the method, then with my skills :P).

1) In my program the array will actually be 2 dimensional. new doesn't make a 2 dimensional array.

2) This class is going to be implemented with an array of the class. I'm not sure how to pass in the dimension when declaring the array of blocks.
Jul 28, 2011 at 3:48pm
I assume you're doing this as a programming exercise? If so, it's easy enough to do with a one dimensional array and a bit of arithmatic.

I would just define getAt(x,y) and setAt(x,y,value) member for your class. With a bit more work you can get the class to act like a normal 2D array, but it's not going to simplify the classes use that much. So unless you want a little programming challenge.

There are plenty of solutions to this problem on the net. So once you have your version working, you could compare it with other peoples.

I'm not sure I get your second question. std::vector's size can be declared either when it's constructed or by calling resize(). You could follow the same approach.
Jul 28, 2011 at 5:22pm
I'm doing this as part of an internship rewriting a simulation for parallel use. Basically, I have an existing block class that has a member array that's hard coded to 12x12 at the moment. I want to generalize it to an nxn array. Rewriting it using dynamic allocation seems to require more and more time as I look into it. Plus it's overkill. The array dimension will be a parameter at the beginning of the code with the rest. It will be known at compile time and it will not change throughout the execution of the program.

Normally declaring a constant sized array like this:

1
2
const int dimension = 12;
double myArray[dimension];

Is no problem, but I can't get it to work when the array is a member of a class.

The short of it is: I need to declare a 2D member array of a class with constant length which is set by a parameter in main.
Jul 28, 2011 at 8:34pm
I don't think the issue is to much class vs non-class, as the following is fine:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Example
{
private:
	static const int dimension = 12;

	double myArray[dimension];

public:
	Example() {}
	~Example() {}

	double getAt(int i) const;
	void setAt(int i, double df);
};


However, if by parameter you mean a constant size defined in main, you could template the size:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
template <int dimension>
class Example
{
private:
	double myArray[dimension];

public:
	Example() {}
	~Example() {}

	double getAt(int i) const
	{
		static double df = 0.0;
		if((0 <= i) && (dimension > i))
			return myArray[i];
		return df;
	}

	void setAt(int i, double df)
	{
		if((0 <= i) && (dimension > i))
			myArray[i] = df;
	}
};

int main()
{
	const int arraySize = 12;

	Example<arraySize> ex;

	ex.setAt(3, 4);
	double df = ex.getAt(3);

	return 0;
}


A non-constant size variable will - of course - require the class to use a dynamic array.
Last edited on Jul 28, 2011 at 8:35pm
Jul 29, 2011 at 2:46pm
This looks perfect. Thanks!
Topic archived. No new replies allowed.