9

Initializing objects (instances of classes or structs) in C++ can be done in various ways. Some syntaxes evoke a direct-initialization of your object, other syntaxes lead to a copy-initialization. With copy-elision enabled in the compiler, both have identical performance. With copy-elision disabled, there is an additional copy/move constructor call upon every instantiation when you choose for the latter (copy-initialization).

Conclusion: copy-initialization can have a performance-penalty!

From the following question: C++11 member initializer list vs in-class initializer? I can conclude that this would be copy-initialization syntax:

obj s = obj("value");

And this would be direct-initialization syntax:

obj s{"value"};

 
But what about this one:

obj s = {"value"};

And this one:

obj s = obj{"value"};

And this one:

obj s("value");

Or this one:

obj s = "value";

NOTE
Bjarne Stroustrup compares a few initialization styles (but not all) in his book "Programming, Principles and Practice Using C++" 2nd edition, on page 311, §9.4.2:

struct Date {
    int y,m,d;                     //year, month, day
    Date(int y, int m, int d);     //check for valid date and initialize
    void add_day(int n);           //increase the Date by n days
};

...

Date my_birthday;                   //error: my_birthday not initialized
Date today{12,24,2007};             //oops! run-time error
Date last{2000,12,31};              //OK (colloquial style)
Date next = {2014,2,14};            //also OK (slightly verbose)
Date christmas = Date{1976,12,24};  //also OK (verbose style)

Mr. Stroustrup presents these different initialization styles as equal. At least, that's how it looks to me. Nevertheless, it could still be possible that some are direct-initialization and others copy-initialization, since those terms are not yet discussed at that point in the book.


EDIT
The given answers bring up something interesting.
Apparently, this is direct-initialization:

obj s("value");

And this is direct-list-initialization:

obj s{"value"};

As some of you point out, there is a difference. In what way do they actually differ? Would the difference be noticeable in the output of a non-optimizing compiler?

K.Mulier
  • 8,069
  • 15
  • 79
  • 141
  • Is there an `=`? Yes: it's copy initialization. It is direct initialization otherwise. – Rakete1111 Oct 08 '17 at 19:05
  • @Rakete1111 [That doesn't seem to be true](http://coliru.stacked-crooked.com/a/18e4e0f6db8a9bfc). – nwp Oct 08 '17 at 19:19
  • @nwp Sure, if you use braces, it is *-list-initialization, depending on `=`. Sorry and thanks! – Rakete1111 Oct 08 '17 at 19:28
  • @nwp copy-list-initialization is technically a type of copy-initialization per the wording in [dcl.init], even though they have different semantics (and in particular copy-list-initialization for a class type does not necessarily rely on a move/copy constructor). – aschepler Oct 08 '17 at 19:33
  • 1
    Do we not have a canonical "what are all the different ways to initialize stuff and when are there copies" question yet? Maybe we should make one that covers C++17 too. – nwp Oct 08 '17 at 19:52

3 Answers3

9
obj s = obj("value");

This is direct initialization of a prvalue, which is then used to copy initialize the variable s. C++17's prvalue rules make this de-facto direct initialization of s.

obj s{"value"};

This is direct-list-initialization. The "list" part is important. Anytime you apply a braced-init-list for the purposes of initializing an object, you are performing list-initialization.

obj s = {"value"};

This is copy-list-initialization.

obj s = obj{"value"};

This is direct-list-initialization of a prvalue, which is then used to copy initialize the variable s.

obj s("value");

That is direct initialization.

obj s = "value";

That's copy initialization.

Mr. Stroustrup presents these different initialization styles as equal.

They are equal in the sense that they do mostly the same thing. But they're not technically equal; copy-list-initialization cannot call explicit constructors. So if the selected constructor were explicit, the code would fail to compile in the copy-list-initialization cases.

Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
  • 1
    Technically speaking, [direct-initialization](https://wg21.link/dcl.init#16) includes direct-list-initialization. That's why L(E)WG invented ["direct-non-list-initialization"](http://eel.is/c++draft/defns.direct-non-list-init) to describe the initialization performed by `optional` and friends. – T.C. Oct 09 '17 at 04:40
  • Thank you very much. Please have a look at the **EDIT** in my question. I would like to know more about this difference between **direct-initialization** and **direct-list-initialization** :-) – K.Mulier Oct 09 '17 at 08:52
  • @K.Mulier: Go look up "list initialization". That's the principle difference. – Nicol Bolas Oct 09 '17 at 14:25
  • If I may again be particularly pedantic *with regard to C++17*, I would say *"This is direct initialization of 's' from "value", and copy initialization of 's' from the prvalue obj(value)"*. Since, as far as I understand, expressions are not initialized (it's always objects or references), but they can serve as initializers. I would be glad if you could help me resolve this issue: 's' seems to be initialized by more than one expression - transitively. I think that's sound, but perhaps there can still be a formal problem? – Johannes Schaub - litb Oct 12 '17 at 12:57
7

In general:

In copy-initialization, the right-hand side is implicitly converted to a temporary instance of the type T, from which s is subsequently copy/move-constructed.

Mr. Stroustrup presents these different initialization styles as equal.

In many cases the generated (optimized) code is indeed exactly the same. Compilers are allowed to elide the copy construction (even if it has side effects). Modern compilers are well beyond simple optimizations such as this one so you can effectively count on this elision (which is required in C++17).

The difference between copy and direct initialization is nevertheless very important because the semantics are different; for example, invoking constructors declared explicit is only possible in direct-initialization.


1 The form T s = {...}; is copy-list-initialization and follows some special list-initialization rules.

rustyx
  • 80,671
  • 25
  • 200
  • 267
  • There are differences though. For copy-list-initialization, there is no temporary. – Rakete1111 Oct 08 '17 at 19:29
  • 1
    @Rakete1111 - true but there is still a [difference](http://eel.is/c++draft/dcl.init#list-3.2) between *copy-list-initialization* and *direct-list-initialization*. – rustyx Oct 08 '17 at 19:48
  • Thank you very much @RustyX. Please have a look at the EDIT in my question. I would like to know more about this difference between direct-initialization and direct-list-initialization :- – K.Mulier Oct 09 '17 at 08:52
  • @K.Mulier - your EDIT is better suited as a new question. Those are very similar except list-initialization implicitly constructs `std::initializer_list`, which can match a different constructor if you have one accepting `std::initializer_list`. – rustyx Oct 09 '17 at 09:06
2

You can easily look up the answers to these sorts of questions. That said, the simple answer is that an = means copy-initialization. However, T t={...}; is copy-list-initialization, which (unless the braces contain only a T or something derived from it) does not involve a copy! It does, however, disallow the use of non-explicit constructors.

Davis Herring
  • 36,443
  • 4
  • 48
  • 76