Initializing multi-dimensional array in constructor

J

jayharris

I'm having a ton of trouble initializing a multi-dimensional array
inside a constructor, largely because I don't know the size of the
array until runtime. I have a class that looks like this:

class MyClass
{
public:
const int size;
MyClass( const int );
};

MyClass::MyClass( const int s )
: size( s )
{
int (*arrayPtr)[size][size] = new int[size][size][size];
}

When I compile this with g++ (actually, Apple's version of g++, in case
that matters), I get the following error:
myclass.cpp : In constructor 'MyClass::MyClass(int)':
myclass.cpp.8: error: 'MyClass::size' cannot appear in a
constant-expression
myclass.cpp.8: error: 'MyClass::size' cannot appear in a
constant-expression

Can anyone explain why I'm getting this error message, especially since
size is declared const, and also can anyone help me out with what to do
about it? Thanks.

--Jay
 
V

Victor Bazarov

I'm having a ton of trouble initializing a multi-dimensional array
inside a constructor, largely because I don't know the size of the
array until runtime. I have a class that looks like this:

class MyClass
{
public:
const int size;
MyClass( const int );
};

MyClass::MyClass( const int s )
: size( s )
{
int (*arrayPtr)[size][size] = new int[size][size][size];
}

When I compile this with g++ (actually, Apple's version of g++, in
case that matters), I get the following error:
myclass.cpp : In constructor 'MyClass::MyClass(int)':
myclass.cpp.8: error: 'MyClass::size' cannot appear in a
constant-expression
myclass.cpp.8: error: 'MyClass::size' cannot appear in a
constant-expression

Can anyone explain why I'm getting this error message, especially
since size is declared const, and also can anyone help me out with
what to do about it? Thanks.

Please see the FAQ. Creation of multidimensional dynamic arrays is
actually covered in it.

V
 
F

Frederick Gotham

Jay Harris posted:

int (*arrayPtr)[size][size] = new int[size][size][size];


You're going to need to employ more devious tactics, something like:

(I've written this hastily in the last half hour, so expect bugs.)


#include <cassert>

template<class T>
class Accessor2D {
protected:

T *const p;
unsigned const d2;

public:

Accessor2D(T *const parg,unsigned const arg2) : p(parg), d2(arg2)
{
assert(parg);
assert(arg2);
}

T *operator[](unsigned const arg2)
{
assert(arg2);

return p + (arg2 * d2);
}
};


template<class T>
class Accessor3D {
protected:

T *const p;
unsigned const d2;
unsigned const d3;

public:

Accessor3D(T *const parg,unsigned const arg2, unsigned const arg3)
: p(parg), d2(arg2), d3(arg3)
{
assert(parg);
assert(arg2);
assert(arg3);
}


Accessor2D<T> operator[](unsigned const arg1)
{
assert(arg1);

return Accessor2D<T>( p + (arg1 * d2 * d3), d3 );
}
};


/* Now here comes your class */


class MyClass {
public:
unsigned const size;
MyClass(unsigned const);
};

MyClass::MyClass(unsigned const s) : size(s)
{
Accessor3D<int> arr(new int[size*size*size],size,size);

arr[0][0][0] = 5;

arr[0][1][2] = 7;
}

int main()
{
MyClass obj(7);
}
 
A

Andrey Tarasevich

I'm having a ton of trouble initializing a multi-dimensional array
inside a constructor, largely because I don't know the size of the
array until runtime. I have a class that looks like this:

"Size" portion of array types in C++ must be a so called 'integral constant
expression' (ICE). The exact definition of ICE can be found in the language
specification, but the idea is that the size must be known at compile time.
Non-static class data members cannot be used in ICEs. This is what makes the
compiler to complain.

Since in your case array sizes are only known at run-time, there's no way to
achieve what you want with array type or type derived from array type (as the
'int (*)[size][size]' you are trying to use). There are different ways to solve
the problem:

1. Use a 1D array of size 'size * size * size' and simulate a 3D access by
manually transforming the 3D indices into the corresponding the 1D index:

[x][y][z] -> [x * size * size + y * size + z]

(that's, BTW, how built-in arrays work in C/C++)

2. Use the well-known array-of-pointers idiom:

int*** arrayPtr = new int**[size];
// Then for each i
arrayPtr = new int*[size];
// Then for each i, j
arrayPtr[j] = new int[size];

(the above is just an illustration of the idea; the actual implementation can be
done in a neater way).

3. (Might make the most sense out of three) Use
'std::vector said:
class MyClass
{
public:
const int size;
MyClass( const int );
};

MyClass::MyClass( const int s )
: size( s )
{
int (*arrayPtr)[size][size] = new int[size][size][size];
}

When I compile this with g++ (actually, Apple's version of g++, in case
that matters), I get the following error:
myclass.cpp : In constructor 'MyClass::MyClass(int)':
myclass.cpp.8: error: 'MyClass::size' cannot appear in a
constant-expression
myclass.cpp.8: error: 'MyClass::size' cannot appear in a
constant-expression
 
J

jayharris

Thanks. Option 1 seemed the simplest, so I went with it.

Andrey said:
I'm having a ton of trouble initializing a multi-dimensional array
inside a constructor, largely because I don't know the size of the
array until runtime. I have a class that looks like this:

"Size" portion of array types in C++ must be a so called 'integral constant
expression' (ICE). The exact definition of ICE can be found in the language
specification, but the idea is that the size must be known at compile time.
Non-static class data members cannot be used in ICEs. This is what makes the
compiler to complain.

Since in your case array sizes are only known at run-time, there's no way to
achieve what you want with array type or type derived from array type (as the
'int (*)[size][size]' you are trying to use). There are different ways to solve
the problem:

1. Use a 1D array of size 'size * size * size' and simulate a 3D access by
manually transforming the 3D indices into the corresponding the 1D index:

[x][y][z] -> [x * size * size + y * size + z]

(that's, BTW, how built-in arrays work in C/C++)

2. Use the well-known array-of-pointers idiom:

int*** arrayPtr = new int**[size];
// Then for each i
arrayPtr = new int*[size];
// Then for each i, j
arrayPtr[j] = new int[size];

(the above is just an illustration of the idea; the actual implementation can be
done in a neater way).

3. (Might make the most sense out of three) Use
'std::vector said:
class MyClass
{
public:
const int size;
MyClass( const int );
};

MyClass::MyClass( const int s )
: size( s )
{
int (*arrayPtr)[size][size] = new int[size][size][size];
}

When I compile this with g++ (actually, Apple's version of g++, in case
that matters), I get the following error:
myclass.cpp : In constructor 'MyClass::MyClass(int)':
myclass.cpp.8: error: 'MyClass::size' cannot appear in a
constant-expression
myclass.cpp.8: error: 'MyClass::size' cannot appear in a
constant-expression
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,743
Messages
2,569,478
Members
44,898
Latest member
BlairH7607

Latest Threads

Top