How do I pass an array to a constructor?
Solution 1
In this case it might be best to use a reference to the array:
class board
{
int (&state)[64];
public:
board(int (&arr)[64])
: state(arr)
{}
// initialize use a pointer to an array
board(int (*p)[64])
: state(*p)
{}
void print();
};
A couple of advantages - no copying of the array, and the compiler will enforce that the correct size array is passed in.
The drawbacks are that the array you initialize the board
object with needs to live at least as long as the object and any changes made to the array outside of the object are 'reflected' into the object's state. but those drawbacks occur if you use a pointer to the original array as well (basically, only copying the array will eliminate those drawbacks).
One additional drawback is that you can't create the object using a pointer to an array element (which is what array function parameters 'decay' to if the array size isn't provided in the parameter's declaration). For example, if the array is passed through a function parameter that's really a pointer, and you want that function to be able to create a board
object referring to that array.
Solution 2
Attempting to pass an array to a function results in passing a pointer to the first element of the array.
You can't assign arrays, and taking a parameter like T[]
is the same as T*
. So
*state = *arr;
Is dereferencing the pointers to state
and arr
and assigning the first element of arr
to the first element of state
.
If what you want to do is copy the values from one array to another, you can use std::copy
:
std::copy(arr, arr + 64, state); // this assumes that the array size will
// ALWAYS be 64
Alternatively, you should look at std::array<int>
, which behaves exactly like you were assuming arrays behave:
#include <array>
#include <algorithm>
#include <iostream>
class board
{
public:
std::array<int, 64> state;
board(const std::array<int, 64> arr) // or initialiser list : state(arr)
{
state = arr; // we can assign std::arrays
}
void print();
};
void board::print()
{
for (int y=0; y<8; y++)
{
for (int x=0; x<8; x++)
std::cout << state[x + y*8] << " ";
std::cout << "\n";
}
}
int main()
{
// using this array to initialise the std::array 'test' below
int arr[] = {
0, 1, 2, 3, 4, 5, 6, 7,
1, 2, 3, 4, 5, 6, 7, 8,
2, 3, 4, 5, 6, 7, 8, 9,
3, 4, 5, 6, 7, 8, 9,10,
4, 5, 6, 7, 8, 9,10,11,
5, 6, 7, 8, 9,10,11,12,
6, 7, 8, 9,10,11,12,13,
7, 8, 9,10,11,12,13,14 };
std::array<int, 64> test(std::begin(arr), std::end(arr));
board b(test);
b.print();
std::cin.get();
return 0;
}
Solution 3
#include <iostream>
class board
{
public:
int * state; //changed here, you can also use **state
board(int *arr) //changed here
{
state = arr;
}
void print();
};
void board::print()
{
for (int y=0; y<8; y++)
{
for (int x=0; x<8; x++)
std::cout << *(state + x + y*8) << " "; //changed here
std::cout << "\n";
}
}
int main()
{
int test[64] = {
0, 1, 2, 3, 4, 5, 6, 7,
1, 2, 3, 4, 5, 6, 7, 8,
2, 3, 4, 5, 6, 7, 8, 9,
3, 4, 5, 6, 7, 8, 9,10,
4, 5, 6, 7, 8, 9,10,11,
5, 6, 7, 8, 9,10,11,12,
6, 7, 8, 9,10,11,12,13,
7, 8, 9,10,11,12,13,14 };
board b(test);
b.print();
std::cin.get();
return 0;
}
or you can use it as:
class board
{
public:
int state[64];
board(int arr[])
{
for(int i=0;i<64;++i)
state[i] = arr[i];
}
void print();
};
EDIT 1: stable solution
class board
{
public:
int * state; //changed here, you can also use **state
board(int *arr) //changed here
{
state = new int[64];
for(int i=0;i<64;++i)
state[i] = arr[i];
}
void print();
};
Svad Histhana
Updated on July 09, 2022Comments
-
Svad Histhana almost 2 years
I want to pass an array to a constructor, but only the first value is passed--the rest looks like garbage.
Here's a simplified version of what I'm working on:
#include <iostream> class board { public: int state[64]; board(int arr[]) { *state = *arr; } void print(); }; void board::print() { for (int y=0; y<8; y++) { for (int x=0; x<8; x++) std::cout << state[x + y*8] << " "; std::cout << "\n"; } } int main() { int test[64] = { 0, 1, 2, 3, 4, 5, 6, 7, 1, 2, 3, 4, 5, 6, 7, 8, 2, 3, 4, 5, 6, 7, 8, 9, 3, 4, 5, 6, 7, 8, 9,10, 4, 5, 6, 7, 8, 9,10,11, 5, 6, 7, 8, 9,10,11,12, 6, 7, 8, 9,10,11,12,13, 7, 8, 9,10,11,12,13,14 }; board b(test); b.print(); std::cin.get(); return 0; }
Can someone explain why this doesn't work and how to properly pass an array? Also, I don't want to copy the array. (And do I really have to indent every line by 4 spaces for code? That's pretty tedious.)
-
Svad Histhana about 12 yearsI tried your suggestion and got the error "expression must be a modifiable lvalue" for state.
-
Svad Histhana about 12 yearsThank you. However, my program won't compile if I try to change
*state = *arr;
tostate = arr;
I get an error for state saying "expression must be a modifiable lvalue". -
vvnraman about 12 years@SvadHisthana I updated the answer as there was a bug in the previous one. I didn't notice that
state
is declared asint []
which makes it aconst pointer
and hence its address cannot be changed. -
Svad Histhana about 12 yearsThank you. That explains why I'm only getting the first value. I don't want to copy the array, however. Nor do I want to use vectors. Surely there's a way to properly pass an array?
-
Seth Carnegie about 12 years@SvadHisthana nope, you cannot pass a real array by value in C++. You can pass an array by reference though (and that only helps to figure out the size of it) but that's it.
-
Avi about 12 years@SvadHisthana See the last line, it will do it for you
-
Seth Carnegie about 12 yearsYou can't assign arrays like
arrCopy = arrayName
-
Seth Carnegie about 12 years@SvadHisthana remember though that if you do it that way,
state
will point to the same array asarr
and any changes you make to one will be made to the other. Also ifarr
goes out of scope,state
will point to a destroyed array -
Svad Histhana about 12 yearsThank you. Though when I tried compiling your first solution, I received an error for line 6: "only static const integral data members can be initialized within a class" vvnraman's solution seems to be working.
-
Rohit Vipin Mathews about 12 yearswhich is the line? i cant find any assignment of class members outside constructor
-
Al Riddoch about 12 yearsYour first example doesn't compile. You can't initialize a member outside a function using new(). A second issue is that the constructor doesn't copy the contents of the array into the allocated block of memory. It just re-assigns the pointer to point to the array passed into the constructor. This would work in your example code, but in a real program, that memory would become invalid as soon as the array test goes out of scope. The memory allocated and assigned to state would just be leaked.
-
Svad Histhana about 12 yearsThank you, but I don't want to copy the array. vvnraman's solution seems to be working for me.
-
Svad Histhana about 12 yearsI wasn't intending to pass by value. vvnraman's solution is what I was going for. Sorry if I didn't phrase my question better. Thanks for your help!
-
Rohit Vipin Mathews about 12 yearsoh sorry i didnt see it was outside constructor. yeah you can assign memory inside the constructor and copy array contents to avoid out of scope issues.
-
Christian Ammer about 12 years@SethCarnegie: You have reversed the
std::copy
arguments. They are:std::copy(first, last, output)
. -
Rohit Vipin Mathews about 12 yearsBut you might have scope problems in a bigger program. ie if you orginal array goes out of scope
-
Avi about 12 yearsBeware. That solution will work in this case. However, test is a local variable and a pointer to it won't be valid after the function returns. Of course when main returns the program is done, but you can run into trouble if test wasn't from main. It's a poor design decision to allow this to happen.
-
Seth Carnegie about 12 years@ChristianAmmer thanks, fixed. Feel free to edit my posts for silly mistakes like that.
-
Svad Histhana about 12 yearsGood to know. That was the desired behavior. However, is there any way to preserve
state
in casearr
does go out of scope? -
Svad Histhana about 12 yearsThis works! Thank you. How does this compare with vvnraman's solution? Also, can you explain what
: state(arr)
does? -
vvnraman about 12 yearsTo preserve
state
, you would need to allocate memory for it (state = new int[64];
and then copy the contents ofarr
tostate
(std::copy(arr, arr + 64, state);
). Of course if you are going to do this, you would have to implement the Rule of Three, as now state is a resource. -
Some programmer dude about 12 years@SvadHisthana Just be careful of the drawbacks if you just copy the pointer, as commented by Seth Carnegie on vvnraman's answer.
-
Michael Burr about 12 years
state(arr)
initializes the reference to the array that's passed as the constructor parameter. -
Svad Histhana about 12 years@Avram: Is there any way to keep the array alive independently of
test
without copying it? I guess I don't understand why the array is destroyed whentest
goes out of scope even if another variable is pointing to the array. Can I just maketest
point to something else, or does that affectstate
? -
Svad Histhana about 12 yearsSo there's no way to preserve
state
without copying the array since the original array declaration is bound totest
? I just started learning C++ yesterday, so forgive my naivete. ;) -
Avi about 12 yearsShort answer, no. The thing with a pointer is that it is little more than an int and its value is a memory address. So just like a variable int i in a function is gone when that function ends, so to test is gone when main ends. And just because some pointer has it's address stored test isn't saved any more than i is. If you want to not have it go, then new/delete are the keywords you need to become familiar with.
-
Svad Histhana about 12 yearsCan someone explain why the array is bound to
test
and is thus destroyed when it goes out of scope? If two variables are pointing to the same array, why does one have precedence over the other? -
Svad Histhana about 12 yearsThank you for explaining this. I'll look into new and delete.
-
Michael Burr about 12 years@Svad: the reference is just an alias for the object it's initialized with. The reference has no effect on that object's lifetime. If you need the
board
object to live longer than the array used to initialize it, then I'd suggest copying the array (which you indicated several times you didn't want to do). An alternative might be to useshared_ptr
to manage the array's lifetime; for that you'd need to create the array in dynamic memory somehow. -
Svad Histhana about 12 yearsI don't want to copy because I plan to make a very large number of board objects, and copying an array every time would be costly. So it seems I need to allocate memory. Avram mentioned
new
in another response. I'll also look intoshared_ptr
. Thanks for the explanation and advice. -
NathanOliver over 7 yearsDo note that you can get rid of
arr
in your code. Sincestd::array
is an aggregate you can initialize it like you do a regular array. This cuts out a step.