Constructor Initializer List in C++ - c++

Please first look the code as follow:
class StrBlob
{
public:
StrBlob();
// ....
private:
std::shared_ptr<std::vector<std::string> > data;
}
//initializer empty into data ;
StrBlob::StrBlob()
// : data(std::make_shared<std::vector<std::string> >()) // compile success
{
// data(std::make_shared<std::vector<std::string> >()); // compile error
}
int main()
{
// this statement can compile
std::shared_ptr<std::vector<std::string> >data(std::make_shared<std::vector<std::string> >());
return 0;
}
I want to know why the statement above compiles occurs error? ?
error: no match for call to ‘(std::shared_ptr<std::vector<std::__cxx11::basic_string<char> > >)
(std::shared_ptr<std::vector<std::__cxx11::basic_string<char> > >)’
data(std::make_shared<std::vector<std::string> >());
corresponding knowledge quoted in C++Primer 5th (Chapter 7.5) as follows:
We can often, but not always , ignore the distinction between whether a member is initialized or assigned. Members that are const or references must be initialized. Similarly, members that are of a class type that does not define a default constructor also must be initialized
First I will share my thought.the 'data' member is default initialized before the constructor body starts executing. right? so,the 'data' member inside constructor will copy the object created from the function make_shared.right?

The first one compiles successfully because you initialize data in the member initializer list and such syntax is perfectly valid here. Check this for more information.
The second one is equal to data(...). It is not a constructing of data object, compiler sees it like an attempt of calling operator() for the data member which is already created (and it says about it in the error message).
Finally inside the main function you simply use shared_ptr copy constructor to create data from the shared_ptr returned by make_shared.

If you want to initialize data object later for many reasons, you can use std::shared_ptr default constructor in StrBlob initialization list and in the body of the StrBlob constructor - the reset function:
StrBlob::StrBlob()
: data()
{
data.reset(new std::vector<std::string>());
}

Related

About copy construct

class Wood {
public:
Wood();
Wood(const Wood&); //copy constructor
~Wood();
private:
string price;
};
Wood::Wood(const Wood& orig) {
price(orig.price); **//error, why?**
}
Wood::Wood(const Wood& orig) : price(orig.price) { //rigth
}
If i using the construct initialize and it was correct. But if if using "price(orig.price)" and it will error, why?
The function body of a constructor (the part between the opening and closing braces) is no different the body of any other function. Would you expect this to compile:
std::string a, b;
a(b); // <--- this line?
No, of course not. In order for that to compile, std::string would need something like an operator() overload which takes another string. It doesn't have that.
The code in the initialization list is different. The expressions in an initialization list are not interpreted as normal statements, like those inside a function body. They are interpreted as initializations (e.g. constructor calls). So, in an initialization list, this:
: price(orig.price)
Is equivalent to a statement like this:
std::string price(orig.price);
Except that the type of price doesn't need to be specified, because that was already done in the class definition.
Note that you cannot do member initialization inside the constructor body, because by the time you get there, all members are already initialized. That's why you need the initialization list. You can, of course, do assignment in the constructor body:
price = orig.price;
But that is different than initialization. It won't work for some types (such as const members, reference members, or members without default constructors). And it can be less efficient for some types, since you are constructing first (with the default constructor), and then assigning. But for many types, it doesn't really matter, because a default construction costs practically nothing.
It's incorrect because price is already constructed. You can't call it's copy constructor if it's already constructed.
You have to do something like price = orig.price;
Examine the compile error and you will see why. In the member initializer list, price(orig.price) is direct initialization of the member variable price with the value orig.price. In the body of the copy constructor, price(orig.price) is a call to an overloaded operator() in std::string which accepts a std::string. Since there is no such overload, you get a compile error.

Why do I get this error when I add another constructor?

I will gladly change the title of this thread to something more appropriate once I know what subject this falls under.
If I change the parameters of the error-causing constructor, there is no error.
This error only occurs if I include that exact constructor:
error: no matching function for call to 'Object::Object(Object)'
note: candidates are: Object::Object(Object&)
note: Object::Object()
Code:
#include <iostream>
using namespace std;
class Object {
public:
Object() {} /* default constructor - no problems at all */
Object( Object & toCopy ) {} /* Cause of error, but no error when commented out */
Object func() {
Object obj;
return obj;
}
};
int main() {
Object o = o.func(); /* this is the line that the error is actually on */
return 0;
}
You have declared an unusual and terrible copy constructor, namely one which takes the argument by non-constant reference. This is possible, and it means that no other copy constructor will be defined implicitly. However, it also means that you cannot construct copies from temporary values, since those don't bind to non-constant references.
Unless you had a reason to do what you were doing (maybe you want to define auto_obj :-) ?), you should declare the usual copy constructor with argument Object const & (but make sure to define it correctly!), or just leave it out entirely and rely on the implicitly generated version (as happens when you "comment out the line" in your code); or in C++11 you can default the copy constructor by declaring Object(Object const &) = default;.
(Note that the popular Rule of Three says that you either should not be defining your own, non-trivial copy constructor, or if you do, then you also need a user-defined destructor and assignment operator. Make sure your code is sane.)
the error you got
error: no matching function for call to 'Object::Object(Object)'
note: candidates are: Object::Object(Object&)
note: Object::Object()
means that compiler is looking for appropriate copy constructor for class Object. There is no such function in your class definition: your version cannot be used to bind temporary (see below). The correct version might be defined by yourself with:
Object(const Object& orig) {
// and initialize data here, and return
}
or you can just don't declare such function, and working version will be generated automatically, thus there is no error then as well.
note:
you are trying to define Object( Object & toCopy ) {}. This is not correct because taking non-const reference to temporary means you cannot use this temporary object to create a copy from it in your constructor because temporary objects cannot be assigned to non-const reference.
So to express this diferent way:
-> compiler is searching for copy constructor
-> finds your version
-> and this version tells: I will not do it
Finally:
Object o = o.func();
this is not good idea. Referring to nonstatic members of objects that have not been constructed or have already been destructed is undefined behavior. Make func() static so might be used like Object::func() or call it on properly constructed object.
Try Object(const Object &toCopy) { }
As already pointed out by many previously, the problem is that you only defined a copy constructor taking a reference, but the return of the call of o.func(); is an rvalue, which can only bind to rvalue references or const references, not to regular references.
Your code however has another issue, calling func() on o, which at that point is a yet uninitialized object, is a very bad idea. Maybe you intended to implement the factory idiom? In this case I would advise that you declare Object func(); static, and call it from the scope of Object, like so:
Object o = Object::func();

Use of constructor in C++

This is very trivial question regarding the use of a constructor in C++. I will present in the form of an interview dialogue (it was difficult to present it in any other forms)
interviewer - what is a constructor?
me - constructor are special functions which makes sure that all objects are initialized before their use.
interviewer - what is an initializer list?
me - that is a list where all the initialization happens. A constructor's body is entered only after all the data members are initialized, or some constructor of all the member objects are called.
interviewer - that means initialization is carried out in initializer list, not inside constructor. But you said constructor initialize the object! Didn't you? Do you want to answer my first question.
me - I think constructor does assignment, it calls assignment operator on already initialized member objects.
So my question to you can be
how initializer list works?
what lies between function's starting address & starting braces [{]?
or just answer me how to convince my interviewer.
Technically speaking, your interpretation is accurate. No members may be initialised from inside the ctor body; only in the ctor-initializer. Any member access in the ctor body may only be assignment.
All members are "initialised" before the ctor body is entered.
However, speaking more broadly, since the body always follows the initializer, it's said that — as a unit — the object is initialised once the constructor has ended... including the body.
Partly this is because, again speaking broadly, you might consider initialisation to include some business logic that you must perform in your ctor body, even though this is not the same as actual initialisation of a data member.
You're overthinking it and allowing the interviewer to confuse you.
Initializing the members of an object is not the same thing as initializing the object itself. Just because the members have sane values doesn't mean the object has been constructed. Until the constructor has completed, the object itself has not been properly initialized.
The main things about an initialisation list are efficiency and code readability.
The readability part is self-explanatory, because you know exactly where to look to see where the values are initialised. The efficiency saving comes in the fact that if you assign them values within the code of the constructor instead, then they will be assigned twice: firstly when the object is created they will be assigned the values provided by that datatype's default constructor, then they will be assigned a new value within your object's constructor. The initialisation list just insures that they are initialised with the value you specified to begin with.
for example, here is an example of an initialisation list I used in a Doubly Linked List implementation:
template <typename T>
LinkedList<T>::LinkedList()
: size(0)
, pHead(NULL)
, pTail(NULL)
{
}
Whereas the less efficient version where size, pHead and pTail get assigned twice is shown below:
template <typename T>
LinkedList<T>::LinkedList()
{
size = 0;
pHead = NULL;
pTail = NULL;
}
Essentially, you are correct but the member initializer shouldn't be considered separate from the constructor. The initializer is a part of the constructor and is called before the main body of the constructor.
When you declare an automatic variable of a built-in type, it is both a definition and a declaration. It's a declaration because an identifier is bound to a type and it's a definition because the compiler allocates storage for it.
int var1; // declares/defines var of type int
int var2 = 0; // declares/defines a var of type int and initializes it to 0
An initializer sets the variable with an initial value when it is defined but it's considered defined before the initializer.
int x = 5;
int y = 5;
int main()
{
int x = x; // x is undefined here not 5 because x refers to itself
int y[y];
int size = sizeof(y)/sizeof(int); // size is 5 (y[5]) since y isn't defined until after the enclosing bracket so y referred to the global y in the declaration.
}
There are some variables that must be initialized however. Constants and references.
It is the same with constructors. The point at which the members have been defined is right before the ctor body. This is the order that members and bases are defined when the constructor is called.
virtual base classes
base class
members--in the order in which they were declared
ctor body is executed
After leaving the constructor body, everything has been initialized.
If you don't use the initializer, then you can assume that its already defined when entering the ctor body but you can't assume it has any particular value. Again, constants and references must be initialized in the member initializer.
The initializer list is part of the constructor. Each constructor has its own.

When are member data constructors called?

I have a global member data object, defined in a header (for class MyMainObj) like this.
class MyMainObj
{
MyDataObj obj;
}
MyDataObj has a default constructor.
When is the constructor for MyDataObj called?
Is it called as part of the creation of MyMainObj?
MyDataObj in this case is not a member of MyMainObj, it's a local variable.
But, constructors for data members are called in your class's constructor. The default constructor for every member is called before execution reaches the first line in the constructor, unless you explicitly specify a constructor using an initializer list, in which case that constructor is called instead.
With that code, obj isn't a member of MyMainObj -- it's simply a local object inside that constructor. As such, it'll only be constructed when/if that constructor is invoked.
Concerning your code, you have a function with a variable inside. Upon entering the function, you will run to the line of code that declares the variable, and the constructor will be run then.
But you say "creation of MyMainObj". It's a function, it can only be called, not created.
This is all concerning the title question, "when are members constructed?" This would apply if MyMainObj was a class and not a function.
Your member objects are constructed in the order of which they appear in the class declaration. All objects are full constructed upon entering the constructor. (But this does not include the class itself!)
That is to say, by the time the class enters its constructor, all the members have finished their constructor.
Objects are destructed in reverse order, in the destructor (after the destructor is run).
In a pseudo-diagram:
MyClass
Member1
Member2
Member3
Construction:
Member1
Member2
Member3
MyClass
Destruction:
MyClass
Member3
Member2
Member1
You can manually call the members constructor using an initialization list:
class foo
{
public:
foo(void) : i(0) // construct i with 0.
{
}
int i;
};
There are various question on SO about initialization lists. Initialization list order, Copy-construction initialization list, and more.
Yes, the constructor would be called whenever a MyMainObj instance is created.
I'm a bit confused by the "global member" terminology - the way you've declared that object it would be a local variable inside the constructor. Am I missing something here?
Yes, as other stated the member will be created on the owner class creation, on construction (be it generated by the compiler or with a provided constructor).
The order of creation will be the same as how your members apear in the class declaration. For example :
class MyType
{
Thing a;
Thing b;
Thing d;
Thing c;
};
Whatever constructor is used, whatever the order in a initialization list, the members will be constructed in this order : a, b, d, c. Once it's all done, the constructor code will be executed (if it exists) and only then your whole object will be constructed.
Upon entering an object constructor, memory has already been allocated for it. Then the execution order is as follows:
Base class constructor, if any, as specified in the initialisation list; if not specified, the default constructor is used.
The constructors for the member data, as specified in the initalisation list (default if not specified), in the order they are declared in the class definition. The order in which they are specified in the initialisation list is irrelevant.
The constructor body.
In the example set in the question, the first thing that would be executed upon entering the default constructor of MyMainObj would be the default constructor of MyDataObj to construct the member data obj.
Given a class A:
class A {
MyDataObj obj;
}
If you don't write the constructor for A, the compiler will create one for you, which will create obj as part of constructing A (and destroy obj as part of destroying A.
If you do write a constructor for A, then obj will be created before your constructor runs, although you can reassign it:
class A {
MyDataObj obj;
public:
A() { } // obj created, but the value may or may not be predictable
}
class AA {
MyDataObj obj;
public:
AA()
{
obj = MyDataObj(5);
}
}
class AAA {
MyDataObj obj;
public:
AAA() : obj(5) { } // member initializer list, my preferred method
}
With the third option, the data objects are created before the member initializer list runs, and the values are assigned in the order they are declared in AAA, NOT the order they are listed in the member initializer list.
UPDATE: There is a difference between creation and initialization. Space for the data members (and the base classes, and the data members for the base classes) is always set aside -- which I would call "creation." However, that doesn't mean a useful value is stored in that memory. There are separate rules for whether an object is default initialized, which depend on the type of the data member (primitive, POD, non-POD) and, IIRC, the storage class of the main object (local, static, global). The easiest way to avoid surprises in this area is to simply make sure you explicitly initialize everything.

Why must const members be initialized in the constructor initializer rather than in its body?

Why must class members declared as const be initialized in the constructor initializer list rather than in the constructor body?
What is the difference between the two?
In C++, an object is considered fully initialised when execution enters the body of the constructor.
You said:
"i wanted to know why const must be
intialized in constructor initializer
list rather than in it's body ?."
What you are missing is that initialisation happens in the initialisation list, and assignment happens in the body of the constructor. The steps in logic:
1) A const object can only be initialised.
2) An object has all of its members initialised in the initialisation list. Even if you do not explicitly initialise them there, the compiler will happily do so for you :-)
3) Therefore, putting 1) and 2) together, a member which is const can only ever have a value assigned to it at initialisation, which happens during the initialisation list.
const and reference variables must be initialized on the line they are declared.
class Something
{
private:
const int m_nValue;
public:
Something()
{
m_nValue = 5;
}
};
would produce code equivalent to;
const int nValue; // error, const vars must be assigned values immediately
nValue = 5;
Assigning const or reference member variables values in the body of the constructor is not sufficient.
C++ provides another way of initializing member variables that allows to initialize member variables when they are created rather than afterwards. This is done through use of an initialization list.
You can assign values to variables in two ways: explicitly and implicitly:
view plaincopy to clipboardprint?
int nValue = 5; // explicit assignment
double dValue(4.7); // implicit assignment
Using an initialization list is very similar to doing implicit assignments.
Remember that the member initialization list, used to initialize base and member data objects, is in the definition, not declaration of the constructor.
More on cpp-tutorial and Code Wrangler.
Because constant variables and references must be initialized at time of declaration i.e before use.
But Constructors will assign value to a varaible not initailize the variable therefore you must use initailizier list for constant and references