2D array as instance variable of class - c++

So if I have a class with a 2D array that I want to initialize with two parameters passed into the constructor, how would I do that, I keep running into errors because it won't let me update the two-d array at all in the constructor.
-- Update from the comments:
In my header file I tried both
int array[][]
and
int **array
and then in the .cpp file in the constructor I'm trying to do
array = new int[arg1][arg2]
Neither declaration of the array in the header file worked.

in the constructor I'm trying to do array = new array[arg1][arg2]
You need to specify the array type, like
array = new int[arg1][arg2];
Note that this works in C++11 only - when using older standards, the second array size needs to be const (which is probably not what you want).
There are also some additional articles discussing the same issue:
Multi-Dimensional Arrays
How to "new" a two-dimension array in C++?
Ideally, since you are using C++ anyway, you should use std::vector as proposed in another answer.
Vectors use a lot of overhead though, don't they? I'm trying to keep my memory use light. –
Start with std::vector. Once your application is running properly from a functional perspective, if you are still concerned about memory usage and/or performance, do benchmarking. If you properly encapsulate your 2D array in a class, you can always change the actual implementation of the array with no impact on the code which uses it.
Technically, if you want to make sure that you have one flat memory area which contains your array, you could use a 1-dimensional array to simulate a 2-dimensional array, like in the following code (just to get you the idea, certainly needs some improvement, especially copy construction and assignment operators are missing):
class Array2D {
private:
int *array;
int size1;
public:
Array2D(int arg1, int arg2) {
size1 = arg1;
array = new int[arg1 * arg2];
}
~Array2D() {
delete[] array;
}
int& at(int i1, int i2) {
return array[i1 * size1 + i2];
}
};
int main() {
Array2D array(10, 10);
array.at(2, 2) = 42;
std::cerr << array.at(2, 2);
return 0;
}

Simplest solution would be:
std::vector<std::vector<VALUE>> arr2(X, std::vector<VALUE>(Y));

Here is an 2d array example with bounds check and custom type, based upon the example from Andreas Fester.
#include <stdexcept>
template <typename T>
class Array2D {
private:
T *array;
unsigned int sizeX;
unsigned int sizeY;
public:
Array2D(unsigned int X, unsigned int Y) {
sizeX = X;
sizeY = Y;
array = new T[X * Y];
}
~Array2D() {
delete[] array;
}
T& at(unsigned int X, unsigned int Y) {
if((X > sizeX) || (Y > sizeY))
throw std::out_of_range("Bla bla");
return array[X * sizeX + Y];
}
};
int main() {
double MyValue;
Array2D<double> *MyArray = new Array2D<double>(10, 100);
MyArray->at(1,1) = 10.1;
MyValue = MyArray->at(1,1);
printf("Array value = %3.3f\n", MyValue);
return 0;
}

Related

Pointer casting with unknown array size in C++

how can I cast void pointer to a 2d array (array of pointers to arrays of ints), when I dont know array size at compile time? Is it somehow possible? (I am doing this because, I pass an 2d array of unknow size to a func. So I cast 2d array to a void pointer and then in that func I want it to recast back.)
int i = 5;
int tab1[i][i];
//cast to void pointer
void *p = (void *)tab1;
//and recast back
int (*tab2)[5] = (int (*)[5])p; //this is working
int (*tab3)[i] = (int (*)[i])p; // but this is not
First I suggest to don't use runtime size for array in C/C++, except you using STL vector as an array. so instead of:
int i = 5;
you must use:
const int i = 5;
except you use Vector that is safe and better than intrinsic arrays.
how can I cast void pointer to a 2d array (array of pointers to arrays of ints), when I dont know array size at compile time? Is it somehow possible?
If we talk about C intrinsic array, It is not possible!
why it is not possible?
because C/C++ compiler not aware of your the array size, borders,.... so if you cast your 2d array to 1d array, it is possible. it is the reason that tab2 array can access to first 5th element of your array. really C/C++ compiler cannot distinguish the different of
int a[3][3]
with
int a[3*3]
so You must be aware of at least one dimension of your array:
int main() {
const int i = 3,j = 4;
int tab1[i][j] = {1,2,3,4,5,6,7,8,9,10,11};
//cast to void pointer
void *p = (void *)tab1;
auto a = (int (*)[i][12/i])p;
return 0;
}
In the above example, I aware about i and total count(12) and I calculate the second dimension.
I use auto keyword that very easily inferred the data type.
int i = 5; int tab1[i][i]; is a VLA. It's not standard C++ and should be avoided.
An array-of-pointers-to-arrays (and vector-of-vectors) won't be as efficient as a true 2D array since it's no longer contiguous (int tab1[5][5] is a true 2D array and is stored contiguously in memory, but the dimensions must be known at compile-time).
You can easily create a custom 2D container class that would store the data in a contiguous 1D vector and apply some simple math (x + y*width) to access the elements.
Example:
class Matrix {
std::vector<int> data;
public:
const int width;
const int height;
Matrix(int width, int height) : width(width), height(height), data(width*height) {}
int operator()(int x, int y) const {
return data[y * width + x];
}
int& operator()(int x, int y) {
return data[y * width + x];
}
};
void print(Matrix const& mat) {
for (int y = 0; y < mat.height; y++) {
for (int x = 0; x < mat.width; x++)
std::cout << mat(x, y) << " ";
std::cout << std::endl;
}
}
int main() {
Matrix mat(5, 5);
mat(1, 1) = 1;
mat(2, 2) = 2;
mat(3, 3) = 3;
print(mat);
}
For convenience this overloads the () operator. It's still possible with the [] operator but that will require a proxy class to access the inner dimension(s) and also putting y before x since the dimensions are actually reversed.
int tab1[i][i]; is a non-standard compiler extension for variable length arrays. It is better to avoid this because it is not portable and hard to deal with as you are seeing. You would be better with:
std::vector<std::vector<int>> tab1(i, std::vector<int>(i));
Then your function can simply take this vector:
void foo(const std::vector<std::vector<int>>& array) { ....
how can I cast void pointer to a 2d array (array of pointers to arrays of ints), when I dont know array size at compile time?
You can't. You can only cast to a type that is known at compile time.
What you can do is convert to a pointer to first element of the first row: int* p = static_cast<int*>(tab1);. You can then treat the array as one dimensional1. Converting two dimensional indices to one dimensional requires some trivial math: x, y -> x + y * i.
1 As long as you don't mind the technicality that pointer arithmetic across the sub array boundary might technically not be allowed by the standard. But that rule is silly. If you're concerned about this, then you should create a one dimensional array in the first place.
The problem you are having here is that the size of an array must be defined at compile time.
In your case, you have multiple options:
make i a constexpr like constexpr int i = 5;
use a int ** instead:
int i = 5;
int tab1[i][i];
//cast to void pointer
void *p = (void *)tab1;
// cast to int **
auto tab1_p = (int **)p;
// use it like it was an array
tab1_p[1][3] = 5;

A function which dynamically creates a 2d array

I want to create a dynamic 2d array in a separate function. The size of the array will be determined at runtime.
Pass an array directly:
void foo(int **arr,int width,int height)
{
arr=new int*[width];
for(int i=0;i<height;i++)
{
arr[i]=new int[height];
}
//fill...
}
...
int** array;
foo(array)
doesn't seem to work
Pass an array via a pointer
void foo(int ***arr,int width,int height)
{
*arr=new int*[width];
for(int i=0;i<height;i++)
{
*arr[i]=new int[height];
}
//fill...
}
...
int **array;
foo(&array)
doesnt seem to work either
How do I do that?
I think that your "problem" is caused by ignoring operator precedence
Second code you posted seems to have mistake on line with:
*arr[i]=new int[height];
which should be
(*arr)[i]=new int[height];
Also, as other pointed out, working with raw pointers could sometimes be pretty evil (like in your example with Pointer to Pointer to Pointer), raw pointers could also cause some problems with memory leaks, dangling pointers,etc. Use something "more practical" like std::vector or some of the other STL containers.
(Note: By term "STL", I mean part of Standard library based on STL)
Let's assume you have to create 2d arrays this way (with an int**).
Instead of trying to pass pointers, return the value that denotes the 2d array.
Second, your code had a bug in that you were looping over the height when you should be looping over the width. Your code would have gone into undefined behavior if height > width.
Third, I don't know if you meant width to be the first dimension or height to be the first dimension, so let's assume that what you wrote is what you meant, i.e. width is the first dimension and height is the inner dimension.
int **foo(int width, int height)
{
int **arr = new int*[width];
for(int i=0; i<width; i++)
arr[i]=new int[height];
return arr;
}
//....
int width = 10, height = 10;
int** array = foo(width, height);
Then you have to write code to delete the allocated data:
for (int i = 0; i < width; ++i)
delete [] array [i];
delete [] array;
Now having said the above, and the above should work, a more optimal version is found here, where the data is one contiguous block instead of separate allocated blocks. This reduces the number of times new[] and delete [] would need to be called.
Generally speaking, multidimensional arrays should never, never be created like this. You should be using a single array wrapped in an object that provides row, column, table, etc. access using the operator() function.
You should also never, never be using raw pointers (except in weird, extenuating circumstances) which is why I'm using STL's std::vector class to implement your code.
class array_2d {
public:
array_2d(size_t width, size_t height) :
width(width),
height(height),
_array(width * height)
{}
int & operator()(size_t x, size_t y) {
return _array[y * width + x];
}
const int & operator()(size_t x, size_t y) const {
return _array[y * width + x];
}
std::pair<size_t, size_t> get_size() const {
return std::make_pair<size_t, size_t>(width, height);
}
private:
size_t width, height;
std::vector<int> _array;
};
int main() {
array_2d my_array(5,5);
my_array(3,3) = 7;
std::cout << my_array(3,3) << std::endl;
return 0;
}
====
7
There's a lot of stuff I didn't include (and the code would be significantly more complex if you were to implement this as a raw pointer) but this is a far superior way to write a 2-dimensional (or more dimensions, if you need it) array.

How to initialize int *const *const?

I need a 2d array with fixed width and height that can only change the individual values stored in it. It is declared in a header and later initialized in a source file.
What I found made me try the following snippets; unfortunately questions were about either 1d or non-const arrays and did not match my situation.
int *const *const a = new int[10][10];
int *const *const b = new int[10][10]();
int *const *const c = new int*[10];
for (int i = 0; i < 10; ++i) {
c[i] = new int[10];
}
My hope was in the last example, but how can I use the "inner" arrays of c if they are not initialized and I am not able to initialize them since they are const?
Do I not need a different type for this array? I was thinking about int d[][] but it doesn't have constant width and height.
It seems to me like a paradox (if it exists in the c++ world), am I missing something?
I was thinking about int d[][] but it doesn't have constant width and height.
int d[][] does not make sense (and will be rejected by the compiler). As far as multi-dimensional arrays are concerned, only the first dimension's size can be omitted to denote an incomplete type. The other dimensions' sizes are part of the type. You cannot omit them, much like you cannot omit the int.
In other words, if you have something like int d[5][10], then you can think of it as a one-dimensional array of element type int[10]. Generally, think of multi-dimensional arrays as a special case of one-dimensional arrays. It will make everything easier to understand.
The best solution to your problem in C++ is to create a class with private std::array<T, Width * Height> data; and int width member variables inside, and calculate the array offset from individual x and y arguments in a public member function, for example:
T& operator()(int x, int y)
{
return data[y * width + x];
}
If the dimensions are only known at run-time, then the only thing you have to change is using std::vector instead of std::array. Storage will still be contiguous.
Here is a complete example:
#include <vector>
#include <iostream>
class Matrix
{
public:
Matrix(int width, int height, int value) :
width(width),
data(width * height, value)
{}
int& operator()(int x, int y)
{
return data[y * width + x];
}
private:
int width;
std::vector<int> data;
};
int main()
{
Matrix m(5, 10, 123);
std::cout << m(7, 8) << "\n";
m(7, 8) = 124;
std::cout << m(7, 8) << "\n";
}
My hope was in the last example, but how can I use the "inner" arrays of c if they are not initialized and I am not able to initialize them since they are const?
That's not really true at all:
int * const * const c = new int*[10]
{
new int[10], new int[10], new int[10], new int[10], new int[10],
new int[10], new int[10], new int[10], new int[10], new int[10]
};

C/C++ allocation of arrays of array like objects

I am mostly a C programmer, and I am looking for a fast and elegant solution to do what I want in C++. Let us consider this simple data structure
struct mystruct
{
int * array1;
int * array2;
size_t size;
};
The two pointers array1 and array2 are to be thought as two arrays of length size. I need a huge amount of these (about 2**30 or 1.000.000.000) all of the same small size (about 100). All of them will be deallocated at the exact same time. I can do the following in C with only one call to malloc where K is the number of struct I need and N is the size of the arrays
EDITED VERSION (see the old one below)
size_t NN = N * sizeof(int);
struct mystruct * my_objects = malloc(K * sizeof(struct mystruct));
int * memory = malloc(2*K*NN);
for(i=0; i<K; ++i)
{
my_objects[i].size = N;
my_objects[i].array1 = memory + 2*i*NN;
my_objects[i].array2 = memory + (2*i+1)*NN;
}
...
free(my_objects);
free(memory);
This version does not support very huge K and does not allow me to resize the array. But it is not so hard to design something for that purpose. Is there a way of creating a class in C++ that would be a kind of std::vector<mystruct> with forbidden shrinking and for which the allocation of array1 and array2 would not be based on dynamical allocation for each entry? I do want to minimize the effect of memory allocation since K is very big.
OLD VERSION:
size_t KK = K * sizeof(mystruct);
size_t NN = N * sizeof(int);
struct mystruct * my_objects = (struct mystruct *) malloc(KK + 2*K*NN);
for(i=0; i<K; ++i)
{
my_objects[i].size = N;
my_objects[i].array1 = (int *) (my_objects + KK + 2*i*NN);
my_objects[i].array2 = (int *) (my_objects + KK + (2*i+1)*NN);
}
Here's my literal translation from C to C++ that maintains the same memory layout:
std::unique_ptr<int[]> const memory(new int[2 * K * N]);
std::vector<mystruct> my_objects;
my_objects.reserve(K);
for (int i = 0; i < K; ++i)
{
mystruct const tmp = {N, memory + 2*i*NN, memory + (2*i+1)*NN};
my_objects.push_back(tmp);
}
The following does two memory allocations, one for each vector. Naturally you have to ensure that the ints vector lives longer than mystructs vector, since mystructs's members refer to ints's members.
struct mystruct
{
int* array1;
int* array2;
std::size_t size;
};
std::vector<int> ints(N*2*K);
std::vector<mystruct> mystructs(K);
for (std::size_t i=0; i<K; i++) {
mystruct& ms = mystructs[i];
ms.array1 = &ints[2*N*i];
ms.array2 = &ints[2*N*i+1];
ms.size = N;
}
Update:
As tp1 pointed out, std::vector might reseat its internal array, invalidating all pointers into it. If you never add or remove elements, that is not an issue. If you do, consider using std::deque instead for ints. However then you also have more memory allocations upon construction, see What really is a deque in STL?. Note that sadly C++ does not allow a const std::vector of non-const elements, see Const vector of non-const objects.
Note: Solution created with minimal manual memory handling in mind, before OP edited in that his main requirement was performance due to a very large K. As std::vector still does behind-the-scenes memory allocations, this isn't a fast solution, just an elegant one.
Might be improved with a custom memory allocator, but I think #Simple's answer is better all-around, especially if encapsuled in a wrapper class.
struct MyStruct
{
std::vector< int > array1;
std::vector< int > array2;
std::size_t size;
MyStruct( std::size_t init_size ) :
array1( std::vector< int >( init_size ) ),
array2( std::vector< int >( init_size ) ),
size( init_size )
{}
};
// ...
std::vector< MyStruct > my_objects( K, N );
No dynamic memory allocation at all. (Well, not by you, anyway.)
What you are doing here in C is that allocating an array externally to your struct, and than pointing pointers to the different parts of this array.
You can do exactly the same thing with std::vector<> - have a huge vector defined outside of your struct, and point pointers to different parts of this vector. Same thing exactly.
If N and K are known at compile time, but can be different in different places, then a template will work:
template <int N, int K>
struct Memory {
Memory() {
for (int i=0; i < K; i++) {
mystruct[i].array1 = data1[i];
mystruct[i].array2 = data2[i];
size[i] = N;
}
}
struct mystruct {
int * array1;
int * array2;
size_t size;
} mystructs[K];
int data1[K][N];
int data2[K][N];
};
void f() {
// The constructor sets up all the pointers.
Memory *m<100,200> = new Memory<100,200>();
.....
}
(I've not checked if that compiles.)
If the values are not known then I would not attempt to do this in one allocation; it makes more sense to do two allocations, one for an array of mystruct, and one for the integers. The extra overhead is minimal, and the code is much more maintainable.
struct Memory {
Memory(int N, int K) {
mystructs = new mystruct[K];
data = new int[2*K*N];
for (int i=0; i < K; i++) {
array1[i] = &data1[2*i*N];
array2[i] = &data2[(2*i+1)*N];
size[i] = N;
}
}
struct mystruct {
int * array1;
int * array2;
size_t size;
} mystruct *mystructs;
int *data;
};
(Again, I've not checked that compiles.)
Note that where your code has 2*i*N*sizeof(int) you have a bug because C pointer arithmetic does not count bytes; it counts multiples of the pointer type. In my code I've made this explicit by taking the address of an array item, but the maths is the same.
What you're trying to do can be done using the exact same code in c++.
However, it is utterly inadvisable in c++. The reason c++ has Object-Oriented semantics is to avoid the very situation you're reckoning with. Here's how I would handle this:
struct mystruct {
vector<int> array1;
vector<int> array2;
mystruct(size_t size);
}
mystruct::mystruct(size_t size) {
array1.resize(size);
array2.resize(size);
}
int main() {
vector<mystruct> mystructarray(numOfStructs, numOfElementsOfArray1AndArray2);
//EDIT: You don't need to expressly call the mystruct constructor, it'll be implicitly called with the variable passed into the vector constructor.
//Do whatever
return 0;
}
vector objects can be queried for their size at runtime, so there's no need to store size as a field of mystruct. And since you can define constructors for structs, it's best to handle creation of the object in that way. Finally, with a valid constructor, you can initialize an array of mystruct with a vector, passing in a valid argument for mystruct's constructor to build the vector.
DOUBLE EDIT COMBO: Alright, let's try a different approach.
Based on what you indicated in your comments, it sounds like you need to allocate a LOT of memory. I'm thinking this data has specific meaning in your application, which means it doesn't make a lot of sense to use generic data structures for your data. So here's what I'm proposing:
class mydata {
private:
size_t num_of_sets;
size_t size_of_arrays;
std::vector<int> data;
public:
mydata(size_t _sets, size_t _arrays)
: data(_sets * _arrays * 2),
num_of_sets(_sets),
size_of_arrays(_arrays) {}
int * const array1(size_t);
int * const array2(size_t);
};
int * const mydata::array1(size_t index)
{
return &(data[index*size_of_arrays * 2]);
}
int * const mydata::array2(size_t index)
{
return &(data[index*size_of_arrays * 2 + size_of_arrays]);
}
int main(int argc, char** argv) {
mydata data(16'777'216, 10);
data.array1(5)[5] = 7;
data.array2(7)[2] = 8;
std::cout << "Value of index 5's array1 at index 5: " << data.array1(5)[5] << std::endl;
std::cout << "Value of index 7's array2 at index 2: " << data.array2(7)[2] << std::endl;
//Do Something
return 0;
}

pointers to a class in dynamically allocated boost multi_array, not compiling

I am pretty new to C++ with Boost.
I want an object of class "world" to have an array named "chunk" of type "octreenode". Previously I had an ordinary one-dimensional array, and this worked fine. Now I'm trying to move to using a 3D array with Boost's multi_array functionality, and I'm really not sure what I'm doing wrong.
Simplified code:
class world {
public:
typedef boost::multi_array<octreenode, 3> planetchunkarray; // a boost_multi for chunks
typedef planetchunkarray::index index;
planetchunkarray *chunk;
world(double x,double y,double z,
int widtheast, int widthnorth, int height) :
originx(x), originy(y), originz(z),
chunkseast(widtheast), chunksnorth(widthnorth), chunksup(height) {
chunk = new planetchunkarray(boost::extents[chunksnorth][chunkseast][chunksup]);
planetchunkarray::extent_gen extents;
for (int cz = 0; cz < chunksnorth; ++cz) {
for (int cx = 0; cx < chunkseast; ++cx) {
for (int cy = 0; cy < chunksup; ++cy) {
(*chunk)[cz][cx][cy] = new octreenode(1,72);
}
}
}
}
};
After which if I attempt to make the assignment
root->planet[0]->chunk[0][0][0]->material = 4;
I get the error:
error: base operand of '->' has non-pointer type 'boost::detail::multi_array::sub_array<octreenode, 1u>'|
"octreenode" has the relevant constructor, and this line worked in identical syntax when it was just:
root->planet[0]->chunk[0]->material = 4;
(with a one-dimensional array). Similarly, while it compiled fine with a one-dimensional array, trying to pass the chunk to functions that expect a pointer to an "octreenode" object, such as:
compactoctree(root->planet[p]->chunk[cz][cx][cy], 0, 14);
generates the error
error: cannot convert 'boost::detail::multi_array::sub_array<octreenode, 1u>' to 'octreenode*' for argument '1' to 'short int compactoctree(octreenode*, int, int)'|
Would be very grateful for any suggestions, I'm sure I'm missing something obvious.
Your array is of value type (octreenode), not pointer type (octreenode*)
Therefore you are not supposed to try to assign a pointer to a dynamically allocated octreenode (new is for heap allocation, by default).
Instead, just assign a value:
(*chunk)[cz][cx][cy] = octreenode(1,72);
In fact, there's no reason to use new on the multi array in the first place either:
UPDATE
In the comments it has been raised that more things could be optimized and that you consider that useful additions to the answer about the compilation error.
So here goes: if you indeed want to initialize all array elements with the exact same value,
You can make the loops way more efficient by forgetting about the array shapes for a moment:
std::fill_n(chunk.data(), chunk.num_elements(), octreenode {1, 72});
If you know octreenode is a POD type, you could write
std::uninitialzed_fill_n(chunk.data(), chunk.num_elements(), octreenode {1, 72});
but a smart library implementation would end up calling fill_n anyways (because there's no gain). You can use uninitialized_fill_n if octreenode is not a POD type, but it is trivially destructible.
In fact, there's no reason to use new on the multi array in the first place either. You can just use the constructor initialization list to construct the multi_array member
Live On Coliru
#include <boost/multi_array.hpp>
#include <type_traits>
struct octreenode { int a; int b; };
class world {
public:
world(double x, double y, double z, int widtheast, int widthnorth, int height)
:
originx(x), originy(y), originz(z),
chunkseast(widtheast), chunksnorth(widthnorth), chunksup(height),
chunk(boost::extents[chunksnorth][chunkseast][chunksup])
{
octreenode v = { 1, 72 };
std::fill_n(chunk.data(), chunk.num_elements(), v);
}
private:
double originx, originy, originz;
int chunkseast, chunksnorth, chunksup;
typedef boost::multi_array<octreenode, 3> planetchunkarray; // a boost_multi for chunks
typedef planetchunkarray::index index;
planetchunkarray chunk;
};
int main() {
world w(1,2,3,4,5,6);
}