Initializing an array of objects - c++

I'm currently working on a card game, and I'm having trouble with some initialization code:
// in my class...
Card cards[20];
// in method...
for(int i = 0; i <= 20;i++)
cards++ = new Card(i, /*i as char +*/ "_Card.bmp");
The trouble is that my compiler's telling me that cards++ is not an l-value. I've read up on the whole pointer-array equivalence thing, and I thought I understood it, but alas, I can't get it to work. My understanding is that since cards degrades to a pointer, and the new operator gives me a pointer to the location of my new instance of Card, then the above code should compile. Right?
I've tried using a subscript as well, but isn't cards+i, cards++, and cards[i] just 3 ways of saying the same thing? I thought that each of those were l-values and are treated as pointers.

Card cards[20];
cards is already an array of objects. They are constructed with the default constructor(constructor with no arguments). There is no need to new again. Probably you need a member function equivalent to constructor arguments and assign through it.
for ( int i=0; i<20; ++i ) // array index shouldn't include 20
cards[i].memberFunction(/*....*/);
Even simpler is to use std::vector
std::vector<Card> cards;
for( int i=0; i<20; ++i )
cards.push_back(Card(i, /*i as char +*/ "_Card.bmp"); )

The code Card cards[20]; already creates an array of 20 Card objects and creates them with the default constructor. This may not be what you want given your code.
I would suggest using vector instead.
std::vector<Card> cards;
for(int i = 0; i < 20;i++)
{
cards.push_back(Card(i, /*i as char +*/ "_Card.bmp"));
}
Note that your for loop goes from 0 to 20 and thus one past the end of the array.

If you want to avoid unnecessary constructor calls and unnecessary resizing, then it's more complicated, because C++ normally initialises each objects one-by-one as it's allocated. One workaround is to do it the Java way -- use a loop and an array of pointers, like so:
Card *cards[20];
for (int i=0; i<20; i++) {
cards[i] = new Card(i);
}
Another option is to use malloc to get explicitly uninitialized memory:
Card *cards = malloc(20 * sizeof(Card));
for (int i=0; i<20; i++) {
new (&(cards[i])) Card(i);
}

Well, there is another possibility, when you are ok with your constructors being called automatically at initialization:
// in my class...
Card cards[20] = { Card(0, "0_Card.bmp"), Card(1, "1_Card.bmp"), /* ... */ };
The huge downside is that you cannot use a loop in this case.

An array name, cards in your code, contains the address of the first element of the array. Such addresses are allocated at run time and you cannot change them. Hence the compiler complaining about cards being not an l-value.
But you can definitely specify what those addresses can hold by using a pointer like below:
// in my class...
Card cards[20];
Card *cardsPointer = cards;// Pointer contains the address of the
//1st element of 'cards' array.
// in method...
for(int i = 0; i < 20; i++)
*(cardsPointer++) = Card(i, /*i as char +*/ "_Card.bmp");// Note that
// there is no 'new' operator as 'cardsPointer' has type 'Card *' and
// not 'Card **'. And 'cardsPointer' has type 'Card *' as the array is
// of type 'Card'.

Related

Assign values from vector to dynamic array (C++)

I have a vector of vertices of a line called lineVertices and I am going to pass this data to draw an OpenGL shape, so this vector must be in the form of an array, I'm assuming. I've tried the following code:
float* lineArray = new float[lineVertices.size()]();
for (unsigned i = 0; i < lineVertices.size(); i++) {
lineArray[i] = lineVertices.at(i);
}
However, it appears that the each element of the vector is getting assigned to the first element of the array only. Even though the lineArray identifier is a pointer to the first element, is there another way to access the different elements of the dynamic array?
If it helps, when I am debugging, it says that the size of lineArray is always 1, although lineVertices' size is clearly greater than 1.
I have also tried the code below, but this also does not work.
float* lineArray = &lineVertices[0];
Any help is appreciated!
You can pass a std::vector directly to OpenGL functions taking a pointer to an array. Just use the ::data() member function. Example:
std::vector<float> vec = ...;
glVertex2fv(vec.data()); // only uses the first two elements
OpenGL functions like this take a pointer to one or more elements. This doesn't have to be a raw array created with new; it just has to be a pointer to a consecutive list of elements. Use vector.data() to get a pointer to a std::vector's contents (first element).
If you really want to create a new array with manual memory management, you can do this (same effect as the code you posted):
float* arr = new float[vec.size()]; // NO () - not a constructor, but operator new[]
for (size_t i = 0; i < vec.size(); i++) {
arr[i] = vec[i];
}

Fill a custom integer array with ints

I am creating a class called intArray. It should behave identical to the std::array but only with integers. I got a bit stuck in the constructor where I need to fill the array with zeros, given the size. I am NOT using the std::array, I am just trying to sort of re-create it.
I was thinking along the lines of having n integers (where n is the fixed array size) that are consecutive in memory and a pointer, head, that points to the first integer... Then the rest of the integers could be easily accessed by getting the i'th memory location after the memory location of the data the head is pointing to.
Basically, how should I initialize/fill an array with zeroes inside its constructor?
Is this a valid way to implement the constructor? If so, is there a better way? If not, how should I accomplish this task?
Sorry, it's a confusing question, just comment if you need any clarity.
Here's my constructor so far:
(not sure how to create 'n' independent integers)
intArray::intArray(size_t n){
intArray::size = n;
int num = 0;
intArray::head = num //head is an int*
//have no idea how to do this...
for(int i=0; i<n; i++){
&num + 1 = 0; //trying to set next value in memory to 0
//obviously not gonna work!
}//end loop
}//end of constructor
I greatly appreciate any answers/comments. Let me now if I missed anything, thanks!
Firstly, what you are really doing is recreating vector, not array, because your construction parameter is not required to be known at compile time. With that in mind, you need to be using dynamic memory unless you change your approach to passing the size as a template parameter and storing an actual array instead of pointer (this is exactly how std::array works).
And so, using dynamic memory, the constructor becomes:
intArray::intArray( size_t n )
: head( new int[ n ] )
, currentSize( n )
{
std::fill( head, head + n, 0 );
}
If you don't want to use std::fill, then the equivalent loop is:
for( size_t i = 0; i < n; i++ )
{
head[i] = 0;
}

C++ Pointer of Array of Ints Initialization

I want to have an array accessible by all functions of a class.
I put the array as private variable in the header file.
private:
int* arrayName;
In the .cpp file where I implement the class, the constructor takes in an int value (size) and creates the array. The goal is to fill it up
ClassName::ClassName(int numElements){
arrayName = new int[numElements]; //make arrays the size of numElements
for(int i = 0; i<numElements; i++)
arrayName[i] = 0;
}
I feel like this is quite inefficient. I know you can do int array[5] = {0}; but how do you do it when you don't initially know the size.
If you want to zero-initialize a newed array, just do value-initialize it. This has the effect of zero-initializing its elements:
arrayName = new int[numElements]();
// ^^
But you really want to be using an std::vector<int>.
private:
std::vector<int> vname;
and
ClassName::ClassName(int numElements) : vname(numElements) {}
This way you don't have to worry about deleting an array and implementing copy constructors and assignment operators.
You can use the memset function:
memset(arrayName,0,sizeof(int)*numElements);
This void * memset ( void * ptr, int value, size_t num ); function sets the first num bytes of the block of memory pointed by ptr to the specified value (interpreted as an unsigned char).
To use it you must include the string.h header file.
For more information: http://www.cplusplus.com/reference/cstring/memset/
What you want to do is progressively expand the array on demand.
arrayName = new int[numElements];
for(int i = 0; i<numElements; i++)
arrayName[i] = 0;
The above code (what you gave) will give you an array of size numElements, and THEN the for loop will fill it. This is allocated now, and can't, as I understand it, be simply or easily resized (memset will overwrite previously held values in the array).
You could copy the whole array over every time you want to resize it:
int * oldarr = new int[OldSize];
//fill your old array
int * newarr = new int[NewSize];
for(int i = 0; i<OldSize; i++)
newarr[i] = oldarr[i];
Other than that, you could make the array much larger, or you could use various STLs, such as std::vector. Vector can be increased with a simple push_back function, and allows [] operator access (like arr[5] and whatnot).
Hope this helps!

how to declare an array of objects without calling object constructor

Given a struct like
struct Square
{
Square(Color p_color): color_(p_color) {}
Color color_;
};
how can i declare a two dimensional array and later initialize it. For example,
typedef Square (&Square8x8)[8][8];
Square8x8 initSquares()
{
Square board[ROWS][COLS]; //declare the array
for(int row=0;row<ROWS;row++)
for(int col=0;col<COLS;col++)
{
if(col%2 == 0)
board[row][col]= Square(WHITE); //actual initlization
else
board[row][col] = Square(BLACK);
}
return board;
}
You misunderstand the point of a constructor, which is to ensure an object is always initialized and valid during its entire lifecycle. Thus the invocation of a constructor cannot be in any way delayed or postponed.
It's a typical XY-problem though - you're asking for help with an intended solution, not a problem. The real problem is that you don't want to postpone the constructor, but initialize it later on. Construction and initialization are related subjects, but not identical.
The best solution is to give your class a setColor or initialize function, separate from the constructor. An alternative solution (which is closer to your question) is to declare the array not as objects, but as pointers, and then really instantiate the object later on with new Square(WHITE). I'd go for the first though, the second requires a lot more lifecycle control with explicit deletion.
You need a default constructor for Square which is able to call without parameters. For example:
struct Square
{
Square() {} // <------------------------- For example
Square(Color p_color): color_(p_color) {}
Color color_;
};
Otherwise, you should use pointer to Square and new them later. For example:
struct Square
{
Square(Color p_color): color_(p_color) {}
Color color_;
};
const int ROWS = 8;
const int COLS = 8;
In this case, you should use pointers:
std::unique_ptr<Square> board[ROWS][COLS];
for (int i=0; i<ROWS; i++)
for (int j=0; j<COLS; j++)
board[i][j] = std::unique_ptr<Square>(new Square(RED));
or (for bare pointers)
Square* board[ROWS][COLS];
for (int i=0; i<ROWS; i++)
for (int j=0; j<COLS; j++)
board[i][j] = new Square(RED);
....
// Be careful, you should delete them all
In case you don't want to use a default constructor you can use the constructor you already have.
This solution uses std::vector, which I also recommend you use.
std::vector<Square> myVector( ROWS*COLS, Square(WHITE) );
this will create an array of ROWS * COLS elements, each initialized to the value of Square(WHITE).
You could create a Board class, which uses such a vector inside and offers functionalities such as initializing a board of arbitrary size and indexing a Square in the linear vector based on Row and Column information.
You can also do:
Square board[2][2] = {Square(WHITE), Square(WHITE), Square(WHITE), Square(WHITE) };
but it doesn't really scale well.
Create an array of (smart) pointers instead of an array. One purpose of pointers is so objects can be initialized later.

how to return two dimensional char array c++?

i ve created two dimensional array inside a function, i want to return that array, and pass it somewhere to other function..
char *createBoard( ){
char board[16][10];
int j =0;int i = 0;
for(i=0; i<16;i++){
for( j=0;j<10;j++){
board[i][j]=(char)201;
}
}
return board;
}
but this keeps giving me error
Yeah see what you are doing there is returning a pointer to a object (the array called board) which was created on the stack. The array is destroyed when it goes out of scope so the pointer is no longer pointing to any valid object (a dangling pointer).
You need to make sure that the array is allocated on the heap instead, using new. The sanctified method to create a dynamically allocated array in modern C++ is to use something like the std::vector class, although that's more complicated here since you are trying to create a 2D array.
char **createBoard()
{
char **board=new char*[16];
for (int i=0; i<16; i++)
{
board[i] = new char[10];
for (int j=0; j<10; j++)
board[i][j]=(char)201;
}
return board;
}
void freeBoard(char **board)
{
for (int i=0; i<16; i++)
delete [] board[i];
delete [] board;
}
The best approach is create a board class and make the ctreateBoard function its constructor:
class Board {
private:
char mSquares[16][10];
public:
Board() {
for(int i=0; i<16;i++){
for( int j=0;j<10;j++){
mSquares[i][j]=201;
}
}
// suitable member functions here
};
For information on how to use such a class, there is no substitute for reading a good book. I strongly recommend Accelerated C++ by Andrew Koenig and Barbra Moo.
This approach will not work. If you return a pointer to a local variable you'll run into undefined behaviour. Instead allocate an array on heap with new and copy data into it manually indexing it.
I would really recommend using STL vector<> or boost/multi_array containers for this.
If you must use arrays, then I would recommend using a typedef to define the array.
typedef char[16][10] TBoard;
You could also return
char**
...but then you would need to typecast it to the correct size in order to index it correctly. C++ does not support dynamic multiple dimension arrays.
Also as others have suggested you can't return an object on the stack (i.e., local variable)
Don't return pointer to a local variable, as other mentioned. If I were forced to do what you want to achieve, first I'd go for std::vector. Since you haven't learnt std::vector, here is another way:
void createBoard(char board[16][10])
{
int j =0;int i = 0;
for(i=0; i<16;i++){
for( j=0;j<10;j++){
board[i][j]=(char)201;
}
}
}
You should return char** instead of char*
The simple answer to your question is char**.
Having said that, DON'T DO IT !
Your "board" variable won't last outside createBoard().
Use boost::multi_array and pass it as a reference to createBoard() or return it directly (but if you do that, it will be copied).
You must not return a pointer to a functions local variables because this space gets overwritten as soon as the function returns.
The storage associated with board is on the function's stack.