C++ array in class not initializing properly - c++

I'm making a monopoly game, and I have two arrays of Vectors for coordinates for my 2d array of characters. Below is my board.h where the array is kept in the board class
class Board {
...
Vector propList[40];
Vector coordList[40];
...
public:
...
};
I am getting an error running my program in bash when trying to create the executable, displayed below (there are 2 identical errors for each array)
board.cc:15:8: error: constructor for 'Board' must explicitly initialize the member 'propList' which does not have a default constructor
Board::Board() {
^
./board.h:17:12: note: member is declared here
Vector propList[40];
I have all 40 elements initialized in my board constructor as displayed below
propList[0] = Vector(-1, -1);
propList[1] = Vector(73, 51);
...
propList[39] = Vector(81, 46);
coordList[0] = Vector(81, 54);
coordList[1] = Vector(73, 54);
...
I also tried the following
Vector v = (-1, 1);
propList[0] = v;
...
and receive the same error. Does anybody know what is going on and how to fix it?
edit: I forgot to add my vector code. I had to create a constructor since I can't use C++11 initialization on my computer.
vector.cc
#include "vector.h"
Vector::Vector(int x, int y) : x(x), y(y) {}
vector.h
struct Vector {
Vector(int x, int y);
int x;
int y;
};

In your constructor, these are assignments, not initialization. Constructors have an initialization list specifically for this purpose. Unfortunately, you can't initialize arrays like this.
Here's the initialization list for a simple int member:
class MyClass
{
int myField;
MyClass() :
m_myField(1)// initialization
{
// right here, myField is 1.
myField = 2;// assignment.
}
};
This initializes myField to 1. Then assigns 2, like you're doing in your constructor.
You can't initialize arrays like this, so I would recommend a workaround: A std::vector of Vectors. Yea that's confusing because both are called "vector", but they mean different things. std::vector is a storage container.
std::vector<Vector> propList;
and in your constructor, add Vector objects to the propList
Board::Board()
{
propList.push_back(Vector(-1, -1));
propList.push_back(Vector(73, 51));
...
}
Another solution is to add a default constructor to Vector. But that's a bit dirty compared to using std::vector<>.
In C++11 it may be possible using aggregate initialization in a constructor initialization list. No, it's not possible, period.

Related

Initializing array of Objects in C++ Composition

I wanted to design a composition using C++ as shown below:
#define NUMBER (4)
class wheel {
int radius;
public:
wheel();
wheel(int);
//copy constructors prototype
//getters and setters prototypes
};
wheel::wheel() : radius(1) {}
wheel::wheel(int r) : radius(r) {}
//wheel class copy constructor definition
//wheel class setter and getter definitions
class car {
wheel fourwheels[NUMBER];
public:
car();
};
car::car() {
fourwheels[NUMBER] = {wheel(1), wheel(1), wheel(1), wheel(1)}; //error code
//wheel fourwheels[NUMBER] = {wheel(1), wheel(1), wheel(1), wheel(1)}; //non-error code
}
int main() {
car mycar;
return 0;
}
While compiling the code, I am getting the following error:
error: no match for 'operator=' (operand types are 'wheel' and '<brace-enclosed initializer list>')
Queries:
Why does this error occur ??
When I comment the error code line and uncomment the non-error code line, it works fine. Why do we have to add the type wheel for the array definition?
You are attempting to assign to an array element. And one that's out of range at that.
Using the constructor's initializer list, this will compile, though you should consider using STL containers rather than a raw array.
car::car() : fourwheels{wheel(1), wheel(1), wheel(1), wheel(1)}
{
}
The code you had commented out "worked" because it declared and initialized a new array of four wheels.
Since the default constructor for wheel provides a radius of 1, you could also write:
car::car() : fourwheels{wheel(), wheel(), wheel(), wheel()}
{
}
But, if we used std::array to hold our wheels, we can simplify this further, as the elements of fourwheels will be initialized using the wheel type's default constructor, which we don't have to write.
class car {
std::array<wheel, NUMBER> fourwheels;
};
Why does this error occur ??
Raw arrays are not copy-assignable. That is, the following will not work:
int nums[4] = {};
nums = {1, 2, 3, 4};
That is essentially what you're trying to do in your car constructor. Instead, you need to initialize the fourwheels member in the member initialization list:
car::car()
: fourwheels{wheel(1), wheel(1), wheel(1), wheel(1)}
{}
When I comment the error code line and uncomment the non-error code line, it works fine. Why do we have to add the type wheel for the array definition ??
Because you're not initializing your car class's member there. You're declaring and initializing a different array, also named fourwheels that is local to the constructor body. The class member remains default-initialized.

How to access members of type std::vector

my program has a function to calculate some sum, for this i need to access attributes of objects in vector:
declaration of vector:
class trilateration {
public:
...
std::vector<tip> *potential;
...
};
then in constructor its initialized:
trilateration::trilateration()
{
...
potential = new std::vector<tip>();
...
}
class tip looks like this:
class tip {
public:
double sum;
Point2d *pt;
tip();
tip(double x, double y);
virtual ~tip();
};
tip constructor:
tip::tip(double x, double y)
{
pt = new Point2d(x,y);
sum=0;
}
objects are added to vector in some function like this:
potential->push_back(tip1);
then i want to access some objects in vector like this:
void trilateration::get3points()
{
for(int i=0; i<potential->size(); ++i)
{
for(int j=0; j<potential->size(); ++j)
{
potential[i].sum=potential[i].sum+normalize(potential[i].pt,potential[j].pt);
}
}
}
while compilation im getting follwoing error:
error: ‘class std::vector<tip>’ has no member named ‘sum’
error: ‘class std::vector<tip>’ has no member named ‘pt’
how can i acess these attributes from vector?
EDIT:
after changing potential to be a member of trilateration and pt to be member of tip, program compiled but when it encounters
potential.push_back(tip1);
throws:
*** glibc detected *** ./loktest: malloc(): memory corruption: 0x00792f10 ***
Unless there are strong reasons to have pointer data members and to allocate your objects on the heap using new, don't do that.
Your code seems to use a kind of Java-style, but this is C++, not Java. Enjoy the automatic resource management of C++, and the power of C++ destructors. Just define data members without using pointers and dynamic allocations.
In class trilateration, change from vector<tip>* to vector<tip>:
class trilateration {
public:
...
// WAS std::vector<tip> *potential;
std::vector<tip> potential;
...
};
In trilateration's constructor, you don't need to create the vector dynamically; just delete the line allocating the vector with new:
trilateration::trilateration()
{
...
// REMOVED:
// potential = new std::vector<tip>();
...
}
Note that in your previous code, when you allocated the vector with new, you had to properly delete it in the destructor, and provide proper copy operations (copy constructor and copy assignment), or ban copies marking the aforementioned operations =delete.
Instead, you don't need all this complicated stuff if you have an ordinary simple non-pointer data member.
The same goes for your tip class.
Unless there is a strong reason to have a Point2d* data member, just use a Point2d (non-pointer) data member:
class tip {
public:
double sum;
// WAS: Point2d *pt;
Point2d pt; // <-- note: no pointers here
tip();
tip(double x, double y);
// NOTE: Do you really need a virtual destructor here??
virtual ~tip();
};
Change the constructor as well:
tip::tip(double x, double y)
: pt(x, y), sum(0)
{
// REMOVE:
// pt = new Point2d(x,y);
//sum=0;
}
Your code gets simplified, and you'll avoid some bugs and headaches.
Since trilateration::potential is a std::vector<tip>*, potential[i] is a std::vector<tip> located at trilateration::potential + i. This is not what you want.
for(int j=0; j<potential->size(); ++j)
{
(*potential)[i].sum=potential[i].sum+normalize((*potential)[i].pt,(*potential)[j].pt);
}
is a possible hack. But what you really want is to get rid of all those useless pointers. Make the vector a member variable of your class and stop using new where it is not needed.

C++: multidimensional array initialization in constructor

I want to use a two dimensional array of constant size as a class member in C++. I have problems initializing it in the constructor though.
Here are my non-working tries:
1.)
class A {
public:
int a[2][2];
A();
};
A::A() {
a = {{1,2},{2,4}};
}
yields: error: assigning to an array from an initializer list
2.)
class A {
public:
int a[2][2];
A();
};
A::A() {
int b[2][2] = {{1,2},{2,4}};
a = b;
}
yields: invalid array assignment
3.)
class A {
public:
int **a;
A();
};
A::A() {
int b[2][2] = {{1,2},{2,4}};
a = b;
}
yields: cannot convert ‘int [2][2]’ to ‘int**’ in assignment
I come from C background. I know that I could use std::vector and I am aware of the disadvantages this approach has but since this is an exercise for me I would like to know how to get it working with plain arrays. I should add that I want to work on this array later on. I want to change the stored values but not the size. Maybe that matters as well (I figured a const at the right place could help somehow?).
If you have C++11, you can use this syntax in the constructor definition:
A() : a{{1,2}, {3, 4}} {}
If you don't have C++11, you will need to stick to the wicked old ways:
A() {
a[0][0] = 1;
// etc
}
The first example also uses the constructor init-list, which should always be used to initialize members instead of intializing them in the constructor body.
various multidimensional array in constructor by example:
// int array1[1];
A() : array1{0} {}
// int array2[2][2];
A() : array2{{0}} {}
// int array3[3][3][3];
A() : array3{{{0}}} {}
Try this, it works for bidimensional array (in standard C++):
class A {
public:
int a[2][2];
A();
};
typedef struct{ int a[4]; } array_t;
A::A() {
int at[2][2] = {{1,2},{2,4}};
*(array_t*)a = *(array_t*)at;
}
Ciao
Angelo
Your first variant is extremely close to the right C++11 syntax:
A::A()
: a{{1,2},{2,4}}
{
}
To complement the previous answers (you guys are so fast):
What you were trying to do in case 1 and 2 is array assignment, not permitted, as compiler says ;
But I would like to draw your attention to your third case, that's a grave misconception, specially coming from C as you say.
Assigning to a a pointer to a local variable?

Values from vector differ from the original value

I am confused with C++ vector and ask for help.
I declare a class CBoundaryPoint:
class CBoundaryPoint:
{
public:
double m_param;
int m_index;
}
And then I define a vector:
vector<CBoundaryPoint> vBoundPoints;
CBoundaryPoint bp;
double param;
// other codes
bp.m_param = param;
vBoundPoints.push_back( bp );
It surprises me that for every element in vBoundPoints, the value of m_param is totally different from the given value param. I just don't know why.
For Example:
param = 0.3356;
bp.m_param = param; // so bp.param equals to 0.3356;
vBoundPoints.push_back( bp ); // while (*(vBoundPoints.end()-1)).m_param = -6.22774385622041925e+066; same case to other elements
So what happened and why? I'm using VS2010.
You probably get garbage when you resize the vector or create a vector of a certain size using the size_type constructor. You get default-constructed objects in your vector, and these contain primmitive types. Since you have no user defined default constructor, the values are essentially random, or "garbage".
You can fix this by adding a default constructor to your class:
class CBoundaryPoint:
{
public:
CBoundaryPoint : m_param(), m_index() {} // initializes members to 0. and 0
double m_param;
int m_index;
}

Intitialzing an array in a C++ class and modifiable lvalue problem

I have a basic C++ class .The header looks like this:
#pragma once
class DataContainer
{
public:
DataContainer(void);
~DataContainer(void);
int* getAgeGroup(void);
int _ageGroupArray[5];
private:
int _ageIndex;
};
Now inside the cpp file of the class I want to intialize the _ageGroupArray[5] with default values inside the class contructor like this:
#include "DataContainer.h"
DataContainer::DataContainer(void)
{
_ageGroupArray={20,32,56,43,72};
_ageIndex=10;
}
int* DataContainer::getAgeGroup(void){
return _ageGroupArray;
}
DataContainer::~DataContainer(void)
{
}
Doing it I am getting "Expression must be a modifiable lvalue" on _ageGroupArray line.So is it entirely impossible to initialize an array object in the constructor? The only solution I found was to define the array outside scope identifiers .Any clarification on this will be greatly appreciated.
In the current standard, as you have already noticed, you cannot initialize a member array in the constructor with the initializer list syntax. There are some workarounds, but none of them is really pretty:
// define as a (private) static const in the class
const int DataContainer::_age_array_size = 5;
DataContainer::DataContainer() : _ageIndex(10) {
int tmp[_age_array_size] = {20,32,56,43,72};
std::copy( tmp, tmp+_age_array_size, _ageGroupArray );
}
If the values in the array are always the same (for all object in the class) then you can create a single static copy of it:
class DataContainer {
static const int _ageGroupArraySize = 5;
static const int _ageGroupArray[ _ageGroupArraySize ];
// ...
};
// Inside the cpp file:
const int DataContainer::_ageGroupArray[_ageGroupArraySize] = {20,32,56,43,72};
You can Initialize a array when you Create/Declare it, not after that.
You can do it this way in constructor :
_ageGroupArray[0]=20;
_ageGroupArray[1]=32;
_ageGroupArray[2]=56;
_ageGroupArray[3]=43;
_ageGroupArray[4]=72;
It is important to know that this is Assignment & not Initialization.
try this:
int ageDefault[]={20,32,56,43,72};
memcpy(_ageGroupArray, ageDefault, sizeof(ageDefault));