What difference between these ways of initializing object member variables in C++11 ? Is there another way ? which way is better (performance) ?:
class any { public: obj s = obj("value"); any(){} };
Or
class any { public: obj s; any(): s("value"){} };
Thanks.
The most common benefit of doing this is improved performance. If the expression whatever is the same type as member variable x_, the result of the whatever expression is constructed directly inside x_ — the compiler does not make a separate copy of the object.
Initializer List is used in initializing the data members of a class. The list of members to be initialized is indicated with constructor as a comma-separated list followed by a colon. Following is an example that uses the initializer list to initialize x and y of Point class.
Member initializer list is the place where non-default initialization of these objects can be specified. For bases and non-static data members that cannot be default-initialized, such as members of reference and const-qualified types, member initializers must be specified.
Conclusion: All other things being equal, your code will run faster if you use initialization lists rather than assignment.
No, these are not the same.
The difference between them is the same that applies for direct-initialization vs. copy-initialization, which is subtle but often very confusing.
§12.6.2 [class.base.init]:
The expression-list or braced-init-list in a mem-initializer is used to initialize the designated subobject (or, in the case of a delegating constructor, the complete class object) according to the initialization rules of 8.5 for direct-initialization. [...]
In a non-delegating constructor, if a given non-static data member or base class is not designated by a mem-initializer-id (including the case where there is no mem-initializer-list because the constructor has no ctor-initializer) and the entity is not a virtual base class of an abstract class (10.4), then
— if the entity is a non-static data member that has a brace-or-equal-initializer, the entity is initialized as specified in 8.5;
§8.5 [dcl.init]:
The initialization that occurs in the form
T x = a;
as well as in argument passing, function return, throwing an exception (15.1), handling an exception (15.3), and aggregate member initialization (8.5.1) is called copy-initialization.
Initializing a non-static data member on a member-initializer-list follows the rules of direct-initialization, which doesn't create intermediate temporaries that need to be moved/copied (if compiled without a copy-elision), neither the type of the data member must be copyable/movable (even if the copy is elided). In addition, a direct-initialization introduces an explicit context, while a copy-initialization is non-explicit (if a constructor selected for the initialization is explicit
, the program won't compile).
In other words, the obj s = obj("value");
syntax won't compile if obj
is declared as:
struct obj { obj(std::string) {} obj(const obj&) = delete; };
or:
struct obj { obj(std::string) {} explicit obj(const obj&) {} };
As a more tangible example, while the below won't compile:
struct any { std::atomic<int> a = std::atomic<int>(1); // ill-formed: non-copyable/non-movable std::atomic<int> b = 2; // ill-formed: explicit constructor selected };
this one will:
struct any { std::atomic<int> a; std::atomic<int> b{ 2 }; any() : a(1) {} };
Which way is better (performance) ?
With a copy-elision enabled both have identical performance. With copy-elision disabled, there is an additional copy/move constructor call upon every instantiation when the copy-initialization syntax is used (that obj s = obj("value");
is one of).
Is there another way ?
The brace-or-equal-initializer syntax allows one to perform a direct-list-initialization as well:
class any { public: obj s{ "value" }; any() {} };
Are there any other differences?
Some other differences that are worth mentioning are:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With