Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++11 member initializer list vs in-class initializer?

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.

like image 998
Ahmed T. Ali Avatar asked Dec 08 '14 05:12

Ahmed T. Ali


People also ask

What is the advantage of using member initializer list?

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.

When must you use a member initializer list?

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.

What is a member initializer list?

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.

Is initializer list faster?

Conclusion: All other things being equal, your code will run faster if you use initialization lists rather than assignment.


1 Answers

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]:

  1. 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. [...]

  2. 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]:

  1. 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:

  1. Brace-or-equal-initializer must reside in a header file along with a class declaration.
  2. If both are combined, member-initializer-list takes priority over brace-or-equal-initializer (that is, brace-or-equal-initializer is ignored).
  3. (C++11 only, until C++14) A class that uses brace-or-equal-initializer violates constraints for an aggregate type.
  4. With the brace-or-equal-initializer syntax it's not possible to perform a direct-initialization other than a direct-list-initialization.
like image 158
Piotr Skotnicki Avatar answered Oct 14 '22 15:10

Piotr Skotnicki