Initialize array of objects in constructor - c++

I wrote a class that holds an array of objects, which each expect a pointer to a c-struct in their constructor:
Here's some code:
class TheOtherClass
{
private:
SomeCStruct* m_pCStruct;
int m_ObjIdx;
public:
TheOtherClass::TheOtherClass(SomeCStruct* pCStruct, int ClassIdx)
: m_pCStruct(pCStruct),
m_ObjIdx(ClassIdx)
{}
}
class MyClass
{
private:
TheOtherClass m_objects[4];
SomeCStruct* m_pMyCStruct;
public:
MyClass::MyClass(SomeCStruct* pCStruct)
: m_pMyCStruct(pCStruct)
{
m_objects[4] = {TheOtherClass(&pCStruct, 1), TheOtherClass(&pCStruct, 2),
TheOtherClass(&pCStruct,3), TheOtherClass(&pCStruct, 4)};
}
I'd actually like to initialize the member objects of MyClass in the init list of the constructor but I was reading this isn't possible?
Hence I tried the above approach but I'm always getting the error: "TheOtherClass": no appropriate default constructor available.
Another thing to mention is that the compiler I'm running is a state of the art C++03 compiler ;-) (it's code for a DSP and TI sort of doesn't wants to update the compiler)
Any help would be highly appreciated!

Since MyClass(SomeCStruct* pCStruct) constructor doesn't (can't) initialize the TheOtherClass m_objects in the member initializer list, the m_objects will need to be default constructed at first, and then this member will be reassigned with new value in the body of the MyClass constructor.
The TheOtherClass won't have a synthesized constructor since you have defined (other, non-default) ctor that takes SomeCStruct* and int. Thus, no default constructor for it in your code.
Here, we define a default constructor:
class TheOtherClass {
SomeCStruct* m_pCStruct;
int m_ObjIdx;
public:
TheOtherClass() : m_pCStruct(nullptr), m_ObjIdx(0) {} // Default ctor
TheOtherClass(SomeCStruct* pCStruct, int ClassIdx)
: m_pCStruct(pCStruct),
m_ObjIdx(ClassIdx) {}
};
As to the MyClass. Since you've already pass the argument as a pointer MyClass(SomeCStruct* pCStruct), you don't need to take the address of it (as in &pCStruct).
And the main issue in the MyClass is that the m_objects is of class type TheOtherClass which does not define any operator=, including the one that takes brace-enclosed initializer list. So, you won't be able to do like so:
m_objects[4] = { // The operator '=' has not been defined for the TheOtherClass, also note the subscript
TheOtherClass(pCStruct, 1),
TheOtherClass(pCStruct, 2),
TheOtherClass(pCStruct,3),
TheOtherClass(pCStruct, 4)
};
Again, when you try to list initialize it, it has already been default constructed. Thus, for this approach to work you will need to define such copy-assignment operator to do this kind of assignment to an already default constructed instance of the TheOtherClass. As to how to implement this operator, it will mostly depend on the overall design and other factors which were not mentioned in this thread.
Update
If you will have the following body of the MyClass constructor, it will work:
MyClass(SomeCStruct* pCStruct) : m_pMyCStruct(pCStruct) {
// Assign to default initialized TheOtherClass object
m_objects[0] = TheOtherClass(pCStruct, 1);
}
I would advise you to check these:
Operator overloading
Constructors and member initializer lists

Related

Initializing private member variables of a class

I apologize in advance because some of my verbiage may not be 100% correct.
I will have a class like this:
class ClassName {
private:
AnotherClass class2;
public:
ClassName();
~ClassName();
...
In the constructor of this class, among other things, I put the line
ClassName::ClassName() {
AnotherClass class2;
}
Which is how I thought you were supposed to initialize objects in C++, however I was noticing (through GDB) that two AnotherClass objects were being created. Once on the Constructor definition then again on my initialization line. What is the reasoning behind this? What if I wanted to use a more complicated constructor like AnotherClass(int a, int b), would it create a temporary object then create the correct one shortly after?
AnotherClass class2; creates another local object inside the constructor body, that gets destroyed at the end of the body. That is not how class members are initialized.
Class members are initialized before the constructor body in the member initializer list between the constructor signature and body, starting with a :, like so:
ClassName::ClassName() :
class2(argumentsToPassToClass2Constructor),
anotherMember(42) // just for example
{
/* constructor body, usually empty */
}
If you don't want to pass any arguments to the class2 constructor you don't have to put it in the initializer list. Then its default constructor will be called.
If you simply want to call the default constructor on all of your class members, you can (and should) omit the constructor altogether. The implicitly generated default constructor will do just what you wanted.
What you are doing in your constructor is creating another variable, local only inside the constructor.
Actually, if you do nothing, the default constructor in AnotherClass will be called for the class2 object.
If you want to be explicit, you can use a constructor initializer list:
ClassName::ClassName()
: class2()
{
}
This last method is also the way you call a specific constructor with arguments in AnotherClass, if you need to do that.
ClassName::ClassName() {
AnotherClass class2; // this will create local variable only
}
If AnotherClass will have default constructor, then it will be called for the class2 object by compiler.
If you want to call parametrized constructor then you will have do it in following way:
ClassName::ClassName() :
class2(arguments)
Why to use and How to use initializer list :
Consider the following example:
// Without Initializer List
class MyClass {
Type variable;
public:
MyClass(Type a) { // Assume that Type is an already
// declared class and it has appropriate
// constructors and operators
variable = a;
}
};
Here compiler follows following steps to create an object of type MyClass
Type’s constructor is called first for “a”.
The assignment operator of “Type” is called inside body of MyClass() constructor to assign
variable = a;
And then finally destructor of “Type” is called for “a” since it goes out of scope.
Now consider the same code with MyClass() constructor with Initializer List
// With Initializer List
class MyClass {
Type variable;
public:
MyClass(Type a):variable(a) { // Assume that Type is an already
// declared class and it has appropriate
// constructors and operators
}
};
With the Initializer List, following steps are followed by compiler:
Copy constructor of “Type” class is called to initialize : variable(a). The arguments in initializer list are used to copy construct “variable” directly.
Destructor of “Type” is called for “a” since it goes out of scope.
As we can see from this example if we use assignment inside constructor body there are three function calls: constructor + destructor + one addition assignment operator call. And if we use Initializer List there are only two function calls: copy constructor + destructor call.
This assignment penalty will be much more in “real” applications where there will be many such variables.
Few more scenarios, where you will have to use initializer list only:
Parametrized constructor of base class can only be called using Initializer List.
For initialization of reference members
For initialization of non-static const data members
You are just creating a local variable in this line. In general there are three ways of initializing private members:
Default initialization
If you do nothing on your constructor, the compiler will automatically initialize the private member by calling its default constructor (ctr without parameters)
Assigning them to a value in the ctr body
In this case you have to assign the desired value to your private member by using the assignment operator.
ClassName::ClassName()
{
class2 = AnotherClass(a, b, c); // if the class ctr has some parameters
}
By using the initialization list
In your case it will be something like:
ClassName::ClassName()
: class2(initial_value)
{
}
This is in general the best and efficient option for initializing your class private members since you avoid calling the copy constructor for the passed parameters. This is in general is not an issue unless the copy ctr contains time-consuming operations. The same apply for the option #2 in this case you may have the same issues with the assignment operator
What you did there is to create a new variable with the same name as you member,
By doing this you overshadowed your member variable.
Also, in the process your member constructor was silently called in the ClassName empty initialisation list.
you can initiate the class in two ways:
ClassName::ClassName(): class2() {}
or:
ClassName::ClassName() {
this->class2 = AnotherClass();
}
The first way is better and a must some times.
If you only use empty constructors for your members you won't see the difference, except in performance, because the compiler initialize the member by default in its initialisation list ( the part after the ":", if you don't do that, he does it silently for you... )
But if your member doesn't have an empty constructor, for example:
AnotherClass:: AnotherClass(int a, int b)
if you will try to use the second way on initialisation you will get a message like:
error: constructor for 'Initiator' must explicitly initialize the member 'class2' which does not have a default constructor

How to set size for vector of self-defined object?

I am trying to set size before using vector, but got error info:
error c2512: 'EItem:EItem' : no appropriate default constructor available
// file.h
vector<EItem > *eL;
// file.cpp
eL = new vector<EItem>(100);
What do I need to provide in my own defined object EItem?
As your compiler is saying, you have to define a default constructor for your EItem class :
in .h :
class EItem {
public:
EItem(); // constructor
// ...
};
in .cpp :
EItem::EItem() {}
Or all in one (in .h) :
class EItem {
public:
EItem() {} // constructor
// ...
};
It is the minimum. You can add some arguments to your class and initialize some attributes of your class in the constructor.
In C++, default constructors are significant because they are automatically invoked in certain circumstances:
When an object value is declared with no argument list, e.g. MyClass x; or allocated dynamically with no argument list, e.g. new MyClass or new MyClass(); the default constructor is used to initialize the object
When an array of objects is declared, e.g. MyClass x[10]; or allocated dynamically, e.g. new MyClass [10]; the default constructor is used to initialize all the elements
When a derived class constructor does not explicitly call the base class constructor in its initializer list, the default constructor for the base class is called
When a class constructor does not explicitly call the constructor of one of its object-valued fields in its initializer list, the default constructor for the field's class is called
In the standard library, certain containers "fill in" values using the default constructor when the value is not given explicitly (ex : vector<MyClass>(10);), initializes the vector with 10 elements, which are filled with the default-constructed value of our type.
In the above circumstances, it is an error if the class does not have a default constructor.
There is some good answers on this thread too : When do we need to have a default constructor?
The vector needs to know how much size an EItem takes up, since vector uses an array. A default constructor will be provided, if none other exist in the EItem class. Make sure you have the class defined and the constructor is public.
class EItem
{
public:
EItem();
};
The compiler is pointing you to the right direction: your class EItem does not have a default constructor - hence you should supply one.
Quoted from here:
What happens if we do not declare a default constructor and then
instantiate our class? The answer is that C++ will allocate space for
our class instance, but will not initialize the members of the class
(similar to what happens when you declare an int, double, or other
basic data type).
Without knowing the definition of your EItem class, a minimal example of implementing a default constructor is:
class EItem {
...
public:
...
//this is a minimal default constructor
EItem() {
...
//initialize and set the values for any data members of the class here
...
}
...
}
For more reading on this and more importantly why you should always supply one in your classes, see the following:
http://en.wikipedia.org/wiki/Default_constructor
Your class need to have a default constructor without parameters for it to be able to use a vector like that. If you can't have a default constructor then you need to make a vector of pointer to your class.

Inherited class initializing a custom made class using non-default constructor

So I have searched all over the place and I can not seem to find the answer to this specific question. I am using a winXP with cygwin and gcc 3.4.4 cygming special.
Problem:
I have a class that works as an interface with some abstract methods and protected variables that should be in every class that inherits from this class. Now I also have another class that is a member variable of this interface.
class Bar {
private:
int y;
public:
Bar(int why);
};
Bar::Bar(int why) : y(why) {}
class Foo {
protected:
Bar b;
public:
Foo(int x);
virtual void print_base();
};
Foo::Foo(int x) : b(x+3) // Have to use initializer list here.
{
//this->b(x+3); // doesn't work
}
class DerFoo : public Foo {
protected:
Bar db;
public:
DerFoo(int x);
};
DerFoo::DerFoo(int x) : Foo(x),
db(x+3) // (Bar)(int) being called, works fine
// db(4.0, 30) // no matching function for call to Bar::Bar(double, int)
// note: candidates are Bar::Bar(const Bar&), Bar::Bar(int)
// b(x-3) // doesn't work class DerFoo does not have any field named 'b'
{
//this->b(x - 3); // Doesn't work, error no match for call to (Bar)(int)
//this->db(x + 3); // Doesn't work, error no match for call to (Bar)(int)
}
So the problem as you can see is inside the derived foo class, DerFoo how to initialize b. I have tried member initialization method, but then the compiler doesn't realize about protected variables. So then for some bizarre reason unbeknownst to me, it can not find the constructor in this class. Even though if were to include a "wrong" call to the constructor of a protected member variable (non inherited) it would suggest the correct version of the constructor.
I have no clue still how to do this. Any help is greatly appreciated.
After you declare a variable you have to set it otherwise you will be calling it like a function.
this->b = Bar(x+3);
The preferred way is to use the initializer list to avoid unnecessary copies of Bar. If you do, however, need to set b outside of the constructor the above example is how to do so.
DerFoo's constructors must not (and cannot) initialize b, that's Foo job. DerFoo's constructors are responsible for initializing only DerFoo's immediate subobjects, namely db and the Foo which is a base class of DerFoo. Foo's constructor, in turn, is responsible for initializing b.
The sequence of events is like:
DerFoo's constructor invokes Foo's constructor
Foo's constructor invokes b's constructor
Foo's constructor runs its body, leaving the Foo object completely constructed
DerFoo's constructor invoke's db's constructor
DerFoo's constructor runs its body, leaving the DerFoo object completely constructed.
If, in the DerFoo constructor, you don't like the value that the Foo constructor left in b, you can assign a new value to b, using any one of these syntaxes:
b = Bar(47);
this->b = Bar(47);
this->Foo::b = Bar(47);
Foo::b = Bar(47);
I don't find the question very clear, but let's see if I understood what you are trying to do and how.
DerFoo::DerFoo(int x) : Foo(x), [a]
db(x+3)
// db(4.0,30) [1]
// note: candidates are Bar::Bar(const Bar&), Bar::Bar(int)
// b(x-3) [2]
{
//this->b(x - 3); [3]
//this->db(x + 3); [4]
}
The first error is [1], where the compiler is telling you that there is no constructor of Bar that takes both a double and an int. The error also lists the two possible constructors that you can use: Bar(int), Bar(Bar const &). I am unsure as of what you intended with this line, but you have already figured out (previous line) that by just providing an int the call will work.
[2] b is not a member of DerFoo, and thus cannot be initialized in the initializer list of DerFoo. It is the responsibility of Foo to initialize it's own member and that will happen through the call to the Foo constructor in [a].
[3],[4], both expressions take the form this->member(i). During initialization the syntax member(i) will well, initialize member with the value of i. Outside of initialization the syntax means call operator()( int ) passing the value of i. Those members have already been initialized, but if you want to reset them you need to assign rather than initialize them.
b is inside the Foo class. to access it (for sure) use
Foo::b = Bar(x-3);
You don't have to use an initializer list, you definitely also should use an initializer list at this point.
At construction of an object, before the code of the constructor is entered all member variable are already constructed. If you don't give initializers, they will be default constructed.
Also you cannot construct a variable again, after it already has been constructed. Your
this->b(x+3)
is not telling the compile to construct b it is telling it to call a function named b on your object. Such a function does not exist in your class, hence the error. Note that once an object has been constructed into a variable, there is no way, to ever call the constructor for that variable again (only to change the value).
A value can be changed using = as in most languages. Hence you could do:
Foo::Foo(int x)
{
this->b = Bar(x+3);
}
This means you are creating another nameless Bar object and assigning it's value to this->b. You should be aware, that this means, you will create two Bar objects, when creating a Foo. First the default constructed one, before. The constructor code is entered, then the new nameless one. Then you will finally assign the value to the already constructed object, so this code is much more inefficient than the one, which uses initializer lists.
EDIT:
Since I missed the second doesn't work in the code above here some additional information:
You are also trying to initialize b directly in the constructor of the derived DerFoo object. However once this part of code is reached, it has already been constructed. Hence any attempt to construct it in the derived constructor comes to late.
Hence you either have to add another constructor to Foo which takes the value and use that one in your constructor of DerFoo. This solution is preferable, since it will only construct the Bar object in b once. If you cannot add such a constructor, then you need to use an assignment in the constructor code for DerFoo.
Trying to initialize b directly in the DerFoo constructor will not work even if the scoping operator is used.
DerFoo::DerFoo() : Foo::b(x-3) {}
will still produce an error: http://ideone.com/6H8ZD

Class construction with initial values

I'm new to C++, and the whole idea of classes - I'm still reading a book to try and learn. The book I'm reading says that when I construct a class, I can assign default values by doing this:
class foo {
public:
foo(char c, int i);
private:
char exampleChar;
int exampleInt;
};
foo::foo(char c, int i):
exampleChar(c),
exampleInt(i)
{}
This code (to me) looks very messy, and doesn't follow rules that I'm used to in other languages. My question is, what's the difference between doing the above, and this (below, which I personally think looks a lot cleaner)?
foo::foo(char c, int i) {
exampleChar = c;
exampleInt = i;
}
Sort of things I'm thinking about are: are there performance/efficiency issues if done on a large scale - or is it exactly the same?
The first way, by doing : exampleChar(c), exampleInt(i) is called an initializer list.
If you do it the second way, the two variables are default constructed first1, then you assign them a value. (When the actual body of the constructor is entered, anything that hasn't been initialized by the initializer list is default constructed.) This is a waste of time because you're just overwriting the values anyway. For small types like int or char this isn't a big deal, but when those member variables are large types that would take lots of cycles to construct, you definitely want to use the initializer list.
The second way won't waste time giving them a default value and then overwriting it - it will set their values directly to that value you give it (or call the right constructor if the member is an object).
You can see what we mean by doing this:
class MyClass {
public:
int _i; // our data
// default constructor
MyClass() : _i(0) { cout << "default constructor"; }
// constructor that takes an int
MyClass(int i) : _i(i) { cout << "int constructor"; }
// assignment operator
void operator=(int i) { _i = i; cout << "assignment operator"; }
};
class OtherClass {
public:
MyClass c;
OtherClass() {
c = 54;
}
};
OtherClass oc;
You'll see that
default constructor
assignment operator
is printed. That's two function calls which, for other classes, could be expensive.
If you change the constructor of OtherClass to
OtherClass() : c(54) { }
You'll see that
int constructor
is printed. Just one call compared to two. This is the most efficient way.
Initializer lists are also a must when you
have types that have no default constructor. You have to call the right constructor in the initializer list.
have a const member that you want to give some value (rather than just have permantently the default value
have a reference member. You must use initializer lists on these.
tl;dr: do it because it's at least as fast but never slower than the other way, and sometimes far faster.
1 For built in types like int and char, they are actually not constructed at all; they just have the value of whatever memory they happen to have had previously.
The difference is that the compiler will always initialize all members (in declaration order) prior to the first user-defined constructor statement. In the case of a char and an int, which are both primitive types, 'initialization' actually means 'no initialization' here. However, if you have a member with a constructor that does some actual work, this constructor will be called upfront - if you do
foo::foo() {
myComplexMember = MyComplexClass(42);
}
the compiler did already invoke the MyComplexClass default constructor before your code got called, which is a waste of resources (and a compiler error if the default ctor is not accessible).
By using an initialization list, you can customize the default initialization and avoid doing things for nothing. Obviously, this is the way to go.
There are things you can do like that that you couldn't otherwise.
If one of the members doesn't have a default constructor. That's the only way you could initiate the member at construction. (same goes to base class)
You can assign a value to a const member.
You can assure a defined state for the class before the constructor function starts running.
If a member is a reference it needs to be initialized in the Initialization List. Because references are immutable and can be initialized only once in the beginning (like const)
Well, this is a typical FAQ question: http://www.parashift.com/c++-faq-lite/ctors.html#faq-10.6
In your case, using char and int there are no differences.
General rule: use initialization list as possibile, there are very few cases when you can prefer assignment, for example for improve readability:
MyClass::MyClass
{
a = b = c = d = e = f = 0;
}
is better than
class MyClass::MyClass : a(0), b(0), c(0), d(0), e(0), f(0) { }
If the members had non-trivial constructors, in the code below first the default constructors would be called, then the assignments would be executed, while in the code above they would be initialized only one time. So yes, there may be a performance issue.
There is also a practical issue: if they are const, references, or don't have default constructors, you can't use the version below.
There is a subtle, but important difference between those two options. What you have at the top is called a member initialization list. When the object is created, the members in this list are initialized to whatever you put in the parenthesis.
When you do assignment in the constructor body, the values are being first initialized, and then assigned. I'll post a short example below.
Example 1: Member initialization
class foo
{
public:
foo(char c, int i);
private:
char exampleChar;
int exampleInt;
Bar exampleBar;
};
foo::foo(char c, int i):
exampleChar(c),
exampleInt(i),
exampleBar() //Here, a bar is being default constructed
{
}
Example 2: Constructor Assignment
class foo
{
public:
foo(char c, int i, Bar b);
private:
char exampleChar;
int exampleInt;
Bar exampleBar;
};
foo::foo(char c, int i, Bar b):
//exampleChar(c),
//exampleInt(i),
//exampleBar()
{
exampleChar = c;
exampleInt = i;
exampleBar = someOtherBar; //Here, a bar is being assigned
}
This is where it gets interesting. Note that exampleBar is being assigned. Behind the scenes, a Bar is actually first being default constructed, even though you did not specify that. Furthermore, if your Bar is more complicated then a simple struct, you will need to be sure to implement the assignment operator in order for you to initialize it in this way. Even furthermore, in order to initialize the Bar from another Bar from the member initialization list, you must implement the copy constructor!
Example 3: Copy constructor used in member init
class foo
{
public:
foo(char c, int i, Bar b);
private:
char exampleChar;
int exampleInt;
Bar exampleBar;
};
foo::foo(char c, int i, Bar b):
//exampleChar(c),
//exampleInt(i),
exampleBar(b) //Here, a bar is being constructed using the copy constructor of Bar
{
exampleChar = c;
exampleInt = i;
}
I would get into the habit of using initialisation lists. They will not suffer from problems when somebody changes a char to some object where the default constructor is called first, and also for const correctness for the const values!
foo::foo(char c, int i):exampleChar(c),exampleInt(i){}
This construct is called a Member Initializer List in C++.
It initializes your member exampleChar to a value c & exampleInt to i.
What is the difference between Initializing And Assignment inside constructor? &
What is the advantage?
There is a difference between Initializing a member using initializer list and assigning it an value inside the constructor body.
When you initialize fields via initializer list the constructors will be called once.
If you use the assignment then the fields will be first initialized with default constructors and then reassigned (via assignment operator) with actual values.
As you see there is an additional overhead of creation & assignment in the latter, which might be considerable for user defined classes.
For an integer data type(for which you use it) or POD class members there is no practical overhead.

Static initialization of a struct with class members

I have a struct that's defined with a large number of vanilla char* pointers, but also an object member. When I try to statically initialize such a struct, I get a compiler error.
typedef struct
{
const char* pszA;
// ... snip ...
const char* pszZ;
SomeObject obj;
} example_struct;
// I only want to assign the first few members, the rest should be default
example_struct ex = { "a", "b" };
SomeObject has a public default constructor with no arguments, so I didn't think this would be a problem. But when I try to compile this (using VS), I get the following error:
error C2248: 'SomeObject::SomeObject' : cannot access private member declared in class 'SomeObject'
Any idea why?
Update: Here's the definition of SomeObject
class SomeObject
{
void operator=(const SomeObject&);
SomeObject(const SomeObject&);
public:
SomeObject()
{
// etc
}
// members snipped
}
Your initialization of ex performs copy-initialization. It takes the value on the right and uses it to initialize the variable on the left. For class-type members, the appropriate constructor is used. In your case, that means invoking the copy constructor for SomeObject, but you've made that constructor private, so the compiler is correct in telling you that SomeObject::SomeObject is a private member that can't be accessed.
Although the compiler is allowed to elide the call to the copy constructor and initialize ex.obj directly with the default constructor, that is an optional optimization; it still needs to be allowed to call the copy constructor.
You can either give example_struct a constructor of your own and use that in place of brace initialization, or you can publicize SomeObject's copy constructor.
The rest of the members will be initialized to '0', not "default", right? So it's probably trying to call SomeObject(0), which I'd guess is resolving to a private copy constructor.
It looks like the constructor for SomeObject is private.