Imagine this class:
class Entity {
public:
int x, y;
Entity() : x(0), y(0) { }
Entity(int x, int y) : x(x), y(y) { }
}
And here are multiple ways of initializing the class with what I think I know:
Entity ent1; //Uses the default constructor, so x=0 and y=0
Entity ent2(); //Uses the default constructor, so x=0 and y=0 (Not sure)
Entity ent3(1, 2); //Made constructor, so x=1 and y=2
Entity ent4 = Entity(); //Default constructor, so x=0 and y=0
Entity ent5 = Entity(2, 3); //Made constructor, so x=2 and y=3
I know that's it's possible to make an object on the heap memory, but that's not what I am looking for at this moment.
My question is, what's the difference between these ways of initializing an object?
I'm not sure which one I should use when.
The difference in initialization lies not only in form it takes, but also
in type of entity which is being initialized. In this case it's a class-type object with a defined default constructor, as well as a constructor with parameters.
Entity ent1;
The statement above is default initialization which result in a call of default constructor for the class Entity.
Entity ent2();
The declaration above will be treated by compiler as a function prototype if that's possible. Entity would be returned type of a function ent2, which takes no arguments. It's known as a case of most vexing parse (MVP) and its existence led to appearance of misleading "clever dumb rule": "never use parenthesis".
In statement like this a user-defined constructor that matches list of arguments is invoked for ent3 object:
Entity ent3(1, 2); // calls Entity(int x, int y)
Another case where MVP can strike is something like this:
Entity ent3_1(int(a), int(b)); // It's not what it looks like.
ent3_1 above is not a variable. The statement declares a function with two int parameters. int(a) being same as int a is legacy of C language and declaration syntax there, which ignores "extra" parenthesis.
Entity ent4 = Entity();
ent4 is a proper version of ent2 case until C++11. Default constructor is invoked as part of value initialization. Its form allows to avoid an ambiguity solving principle which makes ent2 and ent3_1 incorrect. Equal sign here is not an assignment, for no operator= call will happen here. It's part of declaration syntax meant to markup the initialization expression.
Entity ent5 = Entity(2, 3);
ent5 is a version of ent3 case. User-defined constructor invoked as part of value initialization.
Your question is tagged as C++11, and C++11 allows uniform initialization syntax:
Entity ent12{}; // This is a legal alternative of ent2 case
Entity ent13{1, 2}; // A call to constructor or member initialization
Entity ent13{ int(a), int(b) }; // Not a function anymore
Entity ent14 = {}; // Not an assignment
Entity ent15 = Entity{2, 3}; // Not an assignment either!
Note that uniform initialization syntax has a caveat. E.g. this line
std::vector<int> v(10);
declares a vector of 10 elements. But this one
std::vector<int> v{10};
declares a vector initialized with single element of type int with value 10. This happens because std::vector has a constructor with following signature defined:
vector( std::initializer_list<T> init, const Allocator& alloc = Allocator() );
In case that you can't use neither () without triggering MVP nor {} without invoking undesired constructor, the value initialization assignment syntax allows to resolve the issue.
Addendum: Must watch CppCon 2018: Nicolai Josuttis “The Nightmare of Initialization in C++”
Related
I've just learned that we can use the standard library type initializer_list<T> to achieve initializing a class instance with a {}-delimited list of elements of type T. E.g.
class X
{
public:
X(initializer_list<int> lst)
{
cout << "initializer-list constructor\n";
}
X(int i, int j, int k)
{
cout << "constructor taking 3 ints\n";
}
};
int main()
{
X a{ 1,2,3 }; // initializer-list constructor
}
To my knowledge, when the compiler sees { 1,2,3 } in the above code, it will first seek for a constructor that takes a initializer_list<int>, and since there is one, it will construct a initializer_list<int> object out of { 1,2,3 }. Had there been no constructor which takes a initializer_list<int>, the compiler will generate code the same as for X a(1,2,3).
If the process I described above is correct, to me there is some "magic" going on here: I don't understand why defining a type (initializer_list) and let a function (the initializer-list constructor) accept an object of that type (say, lst as above) can "change" the way the function is called. By that I mean: the compiler can now understand {} notation so that we need not to have things like X a({1,2,3}), and in such cases prefers the initializer-list constructor to other constructors while treating {} notation as () notation when the initializer-list constructor is absent.
More to the point, can I define a type (say, my own initializer_list) such that when the compiler sees a special form of instantiation of a class (say, a {} initializer list), it will search for a constructor in that class that takes an object of my own initializer_list type, and will treat that special form of instantiation in some other way if such constructor does not exist?
In other words:
class X
{
public:
X(initializer_list<int> lst)
{
cout << "std\n";
}
X(my_initializer_list<int> lst)
{
cout << "user-defined\n";
}
};
int main()
{
X b{ 1,2,3 };
}
Can I implement a my_initializer_list in the global scope so that the X b{ 1,2,3 }; calls X::X(my_initializer_list<int> lst)?
My current guess is, it is a feature of the language itself that, when the compiler sees a {} initializer list, the compiler will always first seek for the constructor that takes a std::initializer_list, rather than a initializer_list defined in any other namespace (by that I mean, such behavior of the compiler is not implemented in the std::initializer_list, but is a feature designed into the compiler in the first place). May I ask if my guess is on the right track?
There is no magic. This is a type of list of initialization, the rules for which are available here: https://en.cppreference.com/w/cpp/language/list_initialization.
Can I implement a my_initializer_list in the global scope so that the X b{ 1,2,3 }; calls X::X(my_initializer_list lst)?
No, this won't do it. Read the above rules - there's a special handling for initializer-list. If there isn't a constructor taking in an intializer-list, the constructor which matches the argument list is picked.
To call X::X(my_initializer_list<int> lst) you'll have to do X b{my_initializer_list{1,2,3 }};
How the braces {} are interpreted when creating an instance of a class is a language feature. That is, we cannot change it so that the next time they are encountered, our custom my_initializer_list contstructor should be selected. What we can control is what happens once it is selected(assuming that it does gets selected by the language rules).
Can I implement a my_initializer_list in the global scope so that the X b{ 1,2,3 }; calls X::X(my_initializer_list<int> lst)?
So as far as i know, i don't think what you proposed is possible/doable as it requires the {} to be interpreted differently.
Imagine if you provided more than one my_initializer_list say like my_initializer_list1, my_initializer_list2, my_initializer_list3 and suppose your class has a constructor corrresponding to each of them, then when you use {} for creating an instance of the class, how can it be decided which of those constructor to select.
class Act {
protected:
string Owner;
double Balance;
public:
explicit Act(int = 0);
double getBalance() { return Balance; };
};
What is the meaning of line of constructor Act(int =0); Need what int=0 would do here.
Explanation
explicit Act (int = 0);
defines a constructor, that construct an Act from an int parameter. The =0 means that if the parameter can be omitted, it will have a default value of 0. The explicit keyword tells the compiler not to use this constructor for making an implicit conversion.
Examples of use
As it is:
Act a1; // Will generate the same code as Act a1(0);
Act a5{}; // Same as above, but using the braced initialization
Act a2(12); // Obvious
Act a3=13; // Ouch ! Compiler error because of explicit
Act a4 = Act(13); // Ok, because now the call is explicit
If you wouldn't have the explicit keyword, then this line would be ok
Act a3=13; // If not explicit, this is the same than Act a3=Act(13);
Important remarks
The default value is not something that is part of the constructor itself, but a behavior that is defined on the caller side, based on the declaration of the constructor known by the caller.
This means that you could include declare the class with different default values in different compilation units. Although strange, this is perfectly valid.
Note that the absence of parameter name in the declaration is not a problem either, because, the parameter name can be declared within the constructor definition:
Act::Act(int x) : Balance((double)x) {
cout <<"Constructor Act with parameter "<<x<<endl;
}
Finally, note that if you want to use the default value by omitting the parameter, but that your constructor has only one parameter, you should either use the syntax form a1 or a5 in the examples above. You should however not use the syntax with empty parentheses because this would be understood as a function declaration:
Act a0(); // Ouch !! function declaration ! Use a0 or a0{} instead.
In order to address your question we must break down what the line does.
The line calls the constructor for the class Act, the int which has no variable name requires the constructor to take an int. However the =0 part is the default parameter telling the constructor that you don't need the int just place a 0 there.
There are four specific cases , where you must specify default initializer list.
Fully discussed here
In short, if you have
Initializer list Required
non-static const data members
data member of reference type
provide params to data members which are objects of other class
provide base class ctor parameters from derived class.
The one drawback to default argument seems to be that the default arguments must be the trailing parameters in the function prototype parameter list. For example:
drawbacks(???) to default arguments
void f(int, int = 2, int = 3); // trailing defaults
void g(int = 1, int = 2, int c); // error
void h(int, int = 3, int); // error
My question is, if my code does not fall in between the 4 required cases for initializer list and always requires all parameters to have default values, i.e. does not lead to the drawbacks to default arguments , which one should I choose and why? What is the best practice?
an example being
// option -1: for the default argument list
// my_array.h
my_array(int a_number_of_elements = 0, int default_val = 0);
//option-2 : default initalizer list
// my_array.h
my_array(int a_number_of_elements, int default_val);
//my_array.cpp
my_array:: my_array(int a_number_of_elements, int default_val)
: my_num_elements(a_num_elements), my_default_value(default_val)
Thanks for looking.
You are dealing with two completely different things here: constructor initializer lists vs default function arguments.
You got most of what you said correctly, but contrary to what you might believe, default constructor arguments do not imply the construction of data members using these values, unless you explicitly state so. Hence, one technique is not a replacement for the other, just separate complementary things.
For example:
// my_array.h
my_array(int a_number_of_elements = 1, int default_val = 0);
//my_array.cpp
my_array:: my_array(int a_number_of_elements, int default_val)
: my_num_elements(a_num_elements), my_default_value(default_val)
will [be expected to] initialize an array with one element of value zero.
If you do not explicitly call the constructors of the data members, then their default constructors, if available, will be called, so the following two are equivalent.
//implicitly default constructing members
my_array:: my_array()
{}
//explicitly default constructing members
my_array:: my_array() :
my_num_elements(), my_default_value()
{}
Regarding the two above, it is always a good idea to leave things explicit for better legibility. As often said, a given code is usually written once, but read many times.
You have a couple misconceptions here:
You are referring to "Constructor Initializer Lists" as initializer_lists
You seem to think that defaulted arguments can only be used separately from "Constructor Initialization Lists"
Lets talk about some principles here:
You'll always want to use a "Constructor Initializer List" for all your variables, not just those of the 4 types you mention. "Constructor Initializer Lists" value initialize, rather than default initializing and requiring you to assign to them in the constructor body
Where possible you'll always want to have a default constructor, as this is required for using your object in standard containers
Defaulting arguments is a great way to prevent code duplication for both a user defined constructor and a user defined default constructor
So using these principles I can say that the answer to your question is yes, that the ideal situation would be to to use both "Constructor Initializer Lists" and default arguments. Resulting in a constructor that looks something like:
my_array(int a_number_of_elements = 0, int default_val = 0) :
my_num_elements(a_number_of_elements),
my_default_value(default_val) {}
I've been programming in C++ a while and I've used both methods:
class Stuff {
public:
Stuff( int nr ) : n( nr ) { }
private:
int n;
}
Or
class Stuff {
public:
Stuff( int nr ) {
n = nr;
}
private:
int n;
}
Note: This is not the same as this, similar but not the same.
What is considered best practice?
Initializer lists are preferred. See FAQ 10.6
One big advantage to using initializers: If an exception is thrown anywhere within the initializer list, the destructors will be called for those members that had already been initialized -- and only for those members.
When you use the contructor body to initialize the object, it's up to you to handle exceptions properly and unwind the object as appropriate. This is usually much harder to get right.
Use the initializer list when possible. For an int, it doesn't matter much either way, but for a more complex member object, you'd end up with the default constructor of the object being called, followed by an assignment to that object, which is likely to end up being slower.
Plus, you have to do it that way anyway for const members or members which don't have a default constructor.
If possible, use the first version.
The first is initializing using intializer lists, and actually calls the constructors of the members.
The second is assignment. If n was of a type with a default constructor, it the would have already been called, and then you'd be assigning to it. If n didn't have a default constructor, you'd be forced to use the first type. Likewise if n was a reference: int &n.
If there are no constructors of you members that directly take one of the parameters to your constructor, it may be worthwhile to add private static functions that can do the conversion for you.
I generally try to do the initializer list when I can. For one thing, this makes it explicit that you are initializing code in the constructor. const memebers have to be initialized this way.
If you just put code in the constructor's body, it is quite possible someone may decide to come along and move a big chunk of it into a non-constructor "setup" routine later.
It can be taken overboard though. I have a coworker who likes to create classes that have 2 pages of initilizer code, no constructor code, and perhaps 2 pages for the entire rest of the class' code. I find that really tough to read.
I want to add that you don't need to declare the initializer list on the Header (.h). It can be done at the implementation of the constructor (which is very common).
So then:
//Stuff.h
class Stuff {
public:
Stuff( int nr );
private:
int n;
}
//Stuff.cpp
Stuff::Stuff(int nr)
: n(nr)
{
//initalize complex members
}
is legal and imo concentrates the initialization of fields where it matters. Sometimes we need to initialize complex members in the body, so you have your initializer list and the complex initialization all in the .cpp file.
The second option is not initialization but assignment. With types that have user defined default constructors, the second option will call the default constructor and later on call the assignment operator (whether user defined or not) to assign the value.
Some types cannot be default initialized: If you have an attribute without default constructor, hold references (constant or not) or have constant attributes they must be initialized in the initializer list.
Arrays can be value-initialized in the initialization list, but not in the constructor body:
class X {
public:
X() : array() {} // value-initializes the array
// equivalent to:
// X() { for ( int i = 0; i < 10; ++i ) array[i]=0; }
private:
int array[10];
};
For POD types, you can value-initialize them in the initialization list but not inside the brackets:
class X {
public:
X() : pod() {} // value-initializes
// equivalent to (but easier to read and subtly faster as it avoids the copy):
// X() { pod = {}; }
private:
PODType pod;
};
Finally, some classes offer functionality through the use of constructors that will be more complex (if achievable) after default construction.
class X
{
public:
X() : v(10) {} // construct a vector of 10 default initialized integers
// equivalent to:
// X() { for ( int i = 0; i < 10; ++i ) v.push_back(0); }
private:
std::vector<int> v;
};
Last, whenever they are in fact equivalent, initialization lists are more idiomatic in C++.
I'm reading this C++ open source code and I came to a constructor but I don't get it ( basically because I don't know C++ :P )
I understand C and Java very well.
TransparentObject::TransparentObject( int w, int x, int y, int z ) :
_someMethod( 0 ),
_someOtherMethod( 0 ),
_someOtherOtherMethod( 0 ),
_someMethodX( 0 )
{
int bla;
int bla;
}
As far I can "deduce" The first line only declares the construtor name, the "::" sounds like "belongs to" to me. And the code between {} is the constructor body it self.
I "think" what's after the paremeters and the first "{" are like methods default parameters or something, but I don't find a reasonable explanation on the web. Most of the C++ constructors that I found in the examples are almost identical to those in Java.
I'm I right in my assumptions? "::" is like belongs to, and the list after params and body are like "default args" or something?
UPDATE:
Thanks for the answers.
May those be called methods? ( I guess no ) and what is the difference of call them within the constructor body
The most common case is this:
class foo{
private:
int x;
int y;
public:
foo(int _x, int _y) : x(_x), y(_y) {}
}
This will set x and y to the values that are given in _x and _y in the constructor parameters. This is often the best way to construct any objects that are declared as data members.
It is also possible that you were looking at constructor chaining:
class foo : public bar{
foo(int x, int y) : bar(x, y) {}
};
In this instance, the class's constructor will call the constructor of its base class and pass the values x and y.
To dissect the function even further:
TransparentObject::TransparentObject( int w, int x, int y, int z ) :
_someMethod( 0 ),
_someOtherMethod( 0 ),
_someOtherOtherMethod( 0 ),
_someMethodX( 0 )
{
int bla;
int bla;
}
The ::-operator is called the scope resolution operator. It basically just indicates that TransparentObject is a member of TransparentObject. Secondly, you are correct in assuming that the body of the constructor occurs in the curly braces.
UPDATE: Thanks for the answers. May those be called methods? ( I guess no ) and what is the difference of call them within the constructor body
There is much more information on this subject than I could possibly ever give you here. The most common area where you have to use initializer lists is when you're initializing a reference or a const as these variables must be given a value immediately upon creation.
You are pretty close. The first line is the declaration. The label left of the :: is the class name and for it to be a constructor, the function name has to be the same as the class name.
TransparentObject::TransparentObject( int w, int x, int y, int z )
In C++ you can optionally put a colon and some initial values for member variables before the start of the function body. This technique must be used if you are initialzing any const variables or passing parameters to a superclass constructor.
:
_someMethod( 0 ),
_someOtherMethod( 0 ),
_someOtherOtherMethod( 0 ),
_someMethodX( 0 )
And then comes the body of the constructor in curly braces.
{
int bla;
int bla;
}
:: Actually means contains (see comments for clarification), however the _someMethods and so forth is what's called an initialisation list. There is plenty of info at the link =]
EDIT: Sorry, my first sentence is incorrect - see the comments.
Yes, :: is the C++ scoping operator which lets you tell the compiler what the function belongs to. Using a : after the constructor declaration starts what is called an initialization list.
The code between the argument list and the {}s specifies the initialization of (some of) the class members.
Initialization as opposed to assignment---they are different things---so these are all calls to constructors.
You're correct. Its a way to set the default values for the class variables. I'm not too familiar with the exact difference between putting them after : and in the function body.
There are usually some good reasons to use an initialization list. For one, you cannot set member variables that are references outside of the initialization list of the constructor. Also if a member variable needs certain arguments to its own constructor, you have to pass them in here. Compare this:
class A
{
public:
A();
private:
B _b;
C& _c;
};
A::A( C& someC )
{
_c = someC; // this is illegal and won't compile. _c has to be initialized before we get inside the braces
_b = B(NULL, 5, "hello"); // this is not illegal, but B might not have a default constructor or could have a very
// expensive construction that shouldn't be done more than once
}
to this version:
A::A( C& someC )
: _b(NULL, 5, "hello") // ok, initializing _b by passing these arguments to its constructor
, _c( someC ) // this reference to some instance of C is correctly initialized now
{}
Without using the initialiser list all class members will simply have their default constructor called so this is the only place that you can control which constructor is called (for non-dynamically allocated members). The same is true for which parent class constructor will be called.
Class members "initialised" within the body of the constructor (i.e. between the {} braces using the = operator) isn't technically initialisation, it's an assignment. For classes with a non-trivial constructor/destructor it can be costly to default construct and then modify through assignment in this way. For reference members you must use the initialiser list since they cannot be changed via the assignment operator.
If the member (or parent class) does not have a default constructor then failing to specify an appropriate constructor in the initialiser list will cause the compiler to generate an error. Otherwise the compiler will insert the default constructor calls itself. For built in types this does nothing so you will have garbage values there.
Note that the order in which you specify the members in the initialiser list does not affect the order in which they are called. It is always the parent class constructor (if any) first, then the class members in the order in which they are defined in the class definition. The order in which you put them in the initialiser list does not matter and can be the source of subtle bugs...
In the contrived example below it looks like the intention is to initialise m_b with value then m_a with m_b, but what actually happens is that m_a is initialised with m_b (which is itself not yet initialised) then m_b gets initialised with value. m_b will just contain garbage!
struct BadInitialiserListExample
{
BadInitialiserListExample(int value) :
m_b(value),
m_a(m_b) // <-- *BUG* this is actually executed first due to ordering below!
{
}
int m_a;
int m_b;
};