C++: multidimensional array initialization in constructor - c++

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?

Related

Fixing initialization of structs for which constructors have been added

A while ago I wrote code resembling this:
struct Thing
{
int a,b;
};
struct Junk
{
double x;
Thing things[10];
};
Junk myjunk[] =
{
{ 23.4, { {10,20}, {30,40} } },
{ 45.6, { {55,66}, {77,88} } }
};
Originally Thing had no constructors - just a flat simple struct to hold a couple integers. myjunk[] is meant to be special hand-written data to feed into something. In real life it has dozens of lines not just two. This code compiled fine.
Then this morning I added constructors to Thing, useful elsewhere in the great scheme of things, for example, to call functions like blarf(Thing(123,456)); and create huge arrays on the heap with 'new'.
struct Thing
{
int a,b;
Thing();
Thing(int _a, int _b);
};
Now it doesn't compile. I get
Error 1 error C2552: 'Junk::things' : non-aggregates cannot be initialized with initializer list
Yes, class with constructors cannot be made this way. What is the quickest simplest fix to get this compiling?
I know C++11 allows some new ways to initialize variables, but it's not clear in this case what's best. I'm not creating a lone Thing, but an array, and that within another struct. 'Junk' will never have a constructor.
Note that there aren't any virtual methods anywhere, and never will be for Thing and Junk. I'm using Visual Studio 2010, and not sure if it's taking source to be C++11 or older C++.
Change {10, 20} to Thing(10, 20) and so forth.
If you make the constructors constexpr conditional on language version then once you upgrade to a modern compiler you will be able to have the objects initialized at compile-time again:
#if __cplusplus >= 201103L
constexpr
#endif
Thing() : a(0), b(0) {}
#if __cplusplus >= 201103L
constexpr
#endif
Thing(int a, int b) : a(a), b(b) {}
Your code is valid since C++11, so your compiler must not support that. What you can do is initialize the arrays like this:
Junk myjunk[] =
{
{ 23.4, { Thing(10,20), Thing(30,40) } },
{ 45.6, { Thing(55,66), Thing(77,88) } }
};
You can add constructor for Junk with follows
Junk(double _x, initializer_list<Thing> tl) : x(_x){
int i = 0;
for (auto & t : tl) {
things[i] = t;
++i;
if (i >= 10) {
break;
}
}
}

C++ array in class not initializing properly

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.

How to initialize a dynamic memory in a non-standard way in C++?

Say I have a class:
class A
{
private:
const int * const v;
public:
A();
}
I want v to be allocated in the initialization list, and I think I can define the following constructor:
A::A():v((int*)malloc(10*sizeof(int))){}
However, what about v has to be allocated in a non-standard way like the following:
cudaMalloc(&v,10*sizeof(int));
Note cudaMalloc is a CUDA API to allocate GPU memory.
(Ignoring the bigger-picture matters of overall design, exception safety etc. and focusing on the question in its most narrow scope)
Abandon the idea of doing in the initializer list and do it in the constructor body instead
A::A() : v(NULL)
{
cudaMalloc(&v, 10 * sizeof(int));
}
Or, alternatively, wrap the allocation function into your own function that returns the pointer
void *wrapped_cudaMalloc(size_t size)
{
void *m = NULL;
cudaMalloc(&m, size);
return m;
}
...
A::A() : v(wrapped_cudaMalloc(10 * sizeof(int)))
{}
Just for the sake of completeness, there's also an ugly convoluted way to do it in the initializer list without creating any wrappers by exploiting the properties of , operator
A::A() : v((cudaMalloc(&v, 10 * sizeof(int)), v))
{}
Note the additional pair of () around the comma-expression, which is needed to satisfy the initialization syntax (otherwise , will be treated as argument separator instead of comma operator).
In addition to AndreyT's excellent post (and his creative use of the comma operator), you could also wrap things up thusly:
class cudaMallocedInt
{
private:
int *v;
public:
cudaMallocedInt(int n)
{
cudaMalloc(&v, n * sizeof(int));
}
cudaMallocedInt(const cudaMallocedInt &o)
{
// Do whatever is appropriate here. Probably some sort of dance.
}
~cudaMallocedInt()
{
// Remember to cudaFree or whatever
}
operator int*()
{
return v;
}
};
class A
{
private:
cudaMallocedInt v;
public:
A()
: v(10)
{
}
...
};
Update: As Johnsyweb pointed out in comments, please be sure to adhere to the Rule of Three to make sure things don't go boom and you waste your weekends tracking down hard to debug errors instead of having fun!

C++ Class design - easily init / build objects

Using C++ I built a Class that has many setter functions, as well as various functions that may be called in a row during runtime.
So I end up with code that looks like:
A* a = new A();
a->setA();
a->setB();
a->setC();
...
a->doA();
a->doB();
Not, that this is bad, but I don't like typing "a->" over and over again.
So I rewrote my class definitions to look like:
class A{
public:
A();
virtual ~A();
A* setA();
A* setB();
A* setC();
A* doA();
A* doB();
// other functions
private:
// vars
};
So then I could init my class like: (method 1)
A* a = new A();
a->setA()->setB()->setC();
...
a->doA()->doB();
(which I prefer as it is easier to write)
To give a more precise implementation of this you can see my SDL Sprite C++ Class I wrote at http://ken-soft.com/?p=234
Everything seems to work just fine. However, I would be interested in any feedback to this approach.
I have noticed One problem. If i init My class like: (method 2)
A a = A();
a.setA()->setB()->setC();
...
a.doA()->doB();
Then I have various memory issues and sometimes things don't work as they should (You can see this by changing how i init all Sprite objects in main.cpp of my Sprite Demo).
Is that normal? Or should the behavior be the same?
Edit the setters are primarily to make my life easier in initialization. My main question is way method 1 and method 2 behave different for me?
Edit: Here's an example getter and setter:
Sprite* Sprite::setSpeed(int i) {
speed = i;
return this;
}
int Sprite::getSpeed() {
return speed;
}
One note unrelated to your question, the statement A a = A(); probably isn't doing what you expect. In C++, objects aren't reference types that default to null, so this statement is almost never correct. You probably want just A a;
A a creates a new instance of A, but the = A() part invokes A's copy constructor with a temporary default constructed A. If you had done just A a; it would have just created a new instance of A using the default constructor.
If you don't explicitly implement your own copy constructor for a class, the compiler will create one for you. The compiler created copy constructor will just make a carbon copy of the other object's data; this means that if you have any pointers, it won't copy the data pointed to.
So, essentially, that line is creating a new instance of A, then constructing another temporary instance of A with the default constructor, then copying the temporary A to the new A, then destructing the temporary A. If the temporary A is acquiring resources in it's constructor and de-allocating them in it's destructor, you could run into issues where your object is trying to use data that has already been deallocated, which is undefined behavior.
Take this code for example:
struct A {
A() {
myData = new int;
std::cout << "Allocated int at " << myData << std::endl;
}
~A() {
delete myData;
std::cout << "Deallocated int at " << myData << std::endl;
}
int* myData;
};
A a = A();
cout << "a.myData points to " << a.myData << std::endl;
The output will look something like:
Allocated int at 0x9FB7128
Deallocated int at 0x9FB7128
a.myData points to 0x9FB7128
As you can see, a.myData is pointing to an address that has already been deallocated. If you attempt to use the data it points to, you could be accessing completely invalid data, or even the data of some other object that took it's place in memory. And then once your a goes out of scope, it will attempt to delete the data a second time, which will cause more problems.
What you have implemented there is called fluent interface. I have mostly encountered them in scripting languages, but there is no reason you can't use in C++.
If you really, really hate calling lots of set functions, one after the other, then you may enjoy the following code, For most people, this is way overkill for the 'problem' solved.
This code demonstrates how to create a set function that can accept set classes of any number in any order.
#include "stdafx.h"
#include <stdarg.h>
// Base class for all setter classes
class cSetterBase
{
public:
// the type of setter
int myType;
// a union capable of storing any kind of data that will be required
union data_t {
int i;
float f;
double d;
} myValue;
cSetterBase( int t ) : myType( t ) {}
};
// Base class for float valued setter functions
class cSetterFloatBase : public cSetterBase
{
public:
cSetterFloatBase( int t, float v ) :
cSetterBase( t )
{ myValue.f = v; }
};
// A couple of sample setter classes with float values
class cSetterA : public cSetterFloatBase
{
public:
cSetterA( float v ) :
cSetterFloatBase( 1, v )
{}
};
// A couple of sample setter classes with float values
class cSetterB : public cSetterFloatBase
{
public:
cSetterB( float v ) :
cSetterFloatBase( 2, v )
{}
};
// this is the class that actually does something useful
class cUseful
{
public:
// set attributes using any number of setter classes of any kind
void Set( int count, ... );
// the attributes to be set
float A, B;
};
// set attributes using any setter classes
void cUseful::Set( int count, ... )
{
va_list vl;
va_start( vl, count );
for( int kv=0; kv < count; kv++ ) {
cSetterBase s = va_arg( vl, cSetterBase );
cSetterBase * ps = &s;
switch( ps->myType ) {
case 1:
A = ((cSetterA*)ps)->myValue.f; break;
case 2:
B = ((cSetterB*)ps)->myValue.f; break;
}
}
va_end(vl);
}
int _tmain(int argc, _TCHAR* argv[])
{
cUseful U;
U.Set( 2, cSetterB( 47.5 ), cSetterA( 23 ) );
printf("A = %f B = %f\n",U.A, U.B );
return 0;
}
You may consider the ConstrOpt paradigm. I first heard about this when reading the XML-RPC C/C++ lib documentation here: http://xmlrpc-c.sourceforge.net/doc/libxmlrpc++.html#constropt
Basically the idea is similar to yours, but the "ConstrOpt" paradigm uses a subclass of the one you want to instantiate. This subclass is then instantiated on the stack with default options and then the relevant parameters are set with the "reference-chain" in the same way as you do.
The constructor of the real class then uses the constrOpt class as the only constructor parameter.
This is not the most efficient solution, but can help to get a clear and safe API design.

C++ new[] into base class pointer crash on array access

When I allocate a single object, this code works fine. When I try to add array syntax, it segfaults. Why is this? My goal here is to hide from the outside world the fact that class c is using b objects internally. I have posted the program to codepad for you to play with.
#include <iostream>
using namespace std;
// file 1
class a
{
public:
virtual void m() { }
virtual ~a() { }
};
// file 2
class b : public a
{
int x;
public:
void m() { cout << "b!\n"; }
};
// file 3
class c : public a
{
a *s;
public:
// PROBLEMATIC SECTION
c() { s = new b[10]; } // s = new b;
void m() { for(int i = 0; i < 10; i++) s[i].m(); } // s->m();
~c() { delete[] s; } // delete s;
// END PROBLEMATIC SECTION
};
// file 4
int main(void)
{
c o;
o.m();
return 0;
}
Creating an array of 10 b's with new and then assigning its address to an a* is just asking for trouble.
Do not treat arrays polymorphically.
For more information see ARR39-CPP. Do not treat arrays polymorphically, at section 06. Arrays and the STL (ARR) of the CERT C++ Secure Coding Standard.
One problem is that the expression s[i] uses pointer arithmetic to compute the address of the desired object. Since s is defined as pointer to a, the result is correct for an array of as and incorrect for an array of bs. The dynamic binding provided by inheritance only works for methods, nothing else (e.g., no virtual data members, no virtual sizeof). Thus when calling the method s[i].m() the this pointer gets set to what would be the ith a object in the array. But since in actuality the array is one of bs, it ends up (sometimes) pointing to somewhere in the middle of an object and you get a segfault (probably when the program tries to access the object's vtable). You might be able to rectify the problem by virtualizing and overloading operator[](). (I Didn't think it through to see if it will actually work, though.)
Another problem is the delete in the destructor, for similar reasons. You might be able to virtualize and overload it too. (Again, just a random idea that popped into my head. Might not work.)
Of course, casting (as suggested by others) will work too.
You have an array of type "b" not of type "a" and you are assigning it to a pointer of type a. Polymorphism doesn't transfer to dynamic arrays.
a* s
to a
b* s
and you will see this start working.
Only not-yet-bound pointers can be treated polymorphically. Think about it
a* s = new B(); // works
//a* is a holder for an address
a* s = new B[10]
//a* is a holder for an address
//at that address are a contiguos block of 10 B objects like so
// [B0][B2]...[B10] (memory layout)
when you iterate over the array using s, think about what is used
s[i]
//s[i] uses the ith B object from memory. Its of type B. It has no polymorphism.
// Thats why you use the . notation to call m() not the -> notation
before you converted to an array you just had
a* s = new B();
s->m();
s here is just an address, its not a static object like s[i]. Just the address s can still be dynamically bound. What is at s? Who knows? Something at an address s.
See Ari's great answer below for more information about why this also doesn't make sense in terms of how C style arrays are layed out.
Each instance of B contains Both X data member and the "vptr" (pointer to the virtual table).
Each instance of A contain only the "vptr"
Thus , sizeof(a) != sizeof(b).
Now when you do this thing : "S = new b[10]" you lay on the memory 10 instances of b in a raw , S (which has the type of a*) is getting the beginning that raw of data.
in C::m() method , you tell the compiler to iterate over an array of "a" (because s has the type of a*) , BUT , s is actualy pointing to an array of "b". So when you call s[i] what the compiler actualy do is "s + i * sizeof(a)" , the compiler jumps in units of "a" instead of units of "b" and since a and b doesn't have the same size , you get a lot of mambojumbo.
I have figured out a workaround based on your answers. It allows me to hide the implementation specifics using a layer of indirection. It also allows me to mix and match objects in my array. Thanks!
#include <iostream>
using namespace std;
// file 1
class a
{
public:
virtual void m() { }
virtual ~a() { }
};
// file 2
class b : public a
{
int x;
public:
void m() { cout << "b!\n"; }
};
// file 3
class c : public a
{
a **s;
public:
// PROBLEMATIC SECTION
c() { s = new a* [10]; for(int i = 0; i < 10; i++) s[i] = new b(); }
void m() { for(int i = 0; i < 10; i++) s[i]->m(); }
~c() { for(int i = 0; i < 10; i++) delete s[i]; delete[] s; }
// END PROBLEMATIC SECTION
};
// file 4
int main(void)
{
c o;
o.m();
return 0;
}