Question

Before the shouts for duplicate begin: I am aware that the following question (and some others) are quite related to this one:

Is there a difference in C++ between copy initialization and direct initialization?

The answers in this question perfectly explains scenarios where copy initialization is not possible and explains the difference of the two and all that stuff. However, my question is more subtle:

Consider the code:

A createA(){...}

A a1 = createA();
A a2(createA());

Assume that A can be implicitly copy constructed and all that stuff, so both initializations of a1 and a2 are fine. There are no side effects in the copy constructor for A, so both initializations are also semantically equivalent. createA() returns directly the type of the variable, not something else that has to be cast first. I think this case is quite common.

So, in this case, where both alternatives are equally applicable and semantically equivalent, which one should I use? Is there a recommendation in the spec or a consensus/best practice in the community or is it just up to me and my coding style which one to use? Has C++11 introduced any difference in comparison to older standards?

Was it helpful?

Solution 2

There's no "always better" answer, it's a matter of style.

When initializing an object from a simple expression of the object's type (such as createA()) I often use copy-init, probably just due to familiarity with the = form of assignment. Otherwise, when the initializer is a different type or there are multiple initializers for the object (e.g. multiple constructor arguments, or aggregate init) I prefer to use C++11 list-initialization (a.k.a uniform initialization syntax), which can be used in more places, e.g. to initialize aggregates as well as classes with user-defined constructors, and cannot be parsed as a function declaration:

A a1{ createA() };

The above form of list-init uses direct-init, whereas this form uses copy-init:

A a2 = { createA() };

When using list-init I prefer the direct-init form without the redundant = sign.

There are a few cases where list-init isn't possible, e.g. when a type has an initializer-list constructor (i.e. one taking a parameter that is a specialization of std::initializer_list) and you want to call a different constructor, but the initializer-list constructor would get chosen, e.g. std::vector<int> v{ 5u, 0 }; will not create a vector of five elements with value zero, but a vector with two elements with values five and zero

OTHER TIPS

If everything else is equal (semantics, performance,...) it's obviously only a matter of taste and/or style convention. However, many authors advocate a list-initializer for direct initialization these days:

A a3 {createA()};

But I'd say it's either up to you (if it's your fun project) or to your coworkers to decide on one of the two (three) alternatives. I would not recommend to use both interchangeably, because that would make readers wonder why you use sometimes direct and sometimes copy initialization.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top