initializer_list - Why is the move constructor called here? O.o

Jun 3, 2016 at 12:01pm
Hello. Look at this code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#include <iostream>

using namespace std;

struct Foo
{
   string n;
   Foo(string str) : n{str}
   {
       cout << "ctor (" << n << ")"<< endl;
   }

   Foo(initializer_list<Foo> ilist)
   {
       cout << "initializer list" << endl;
   }

   Foo(const Foo& copy)
   {
       cout << "copy ctor (copying " << copy.n << ")" << endl;
   }

   Foo(Foo&& move)
   {
       cout << "move ctor (moving " << move.n << " inside " << this->n << ")" << endl;
   }

   ~Foo()
   {
       cout << "Destructor of " << n << endl;
   }

};

int main()
{
   Foo a("Hello");

   Foo b{ a };
}


The output is:

ctor (Hello)
copy ctor (copying Hello)
move ctor (moving inside )
initializer list
Destructor of
Destructor of
Destructor of
Destructor of Hello


IMPORTANT NOTE: I HAVE DISABLED COPY ELISION -fno-elide-constructors

[1] The object 'a' gets constructed, so the first line is clear.

[2] The object 'b' calls the initializer_list constructor passing a copy of 'a'

[3] A move constructor gets called... WHUT???

[4] The cout inside the initializer_list constructor gets finally called!

[5, 6, 7] What the f. are these destructors?? P_P

[8] Destructor of the original object 'a', fine.

Need some clarifications!



Last edited on Jun 3, 2016 at 12:02pm
Jun 3, 2016 at 1:25pm
Step 3: Your temporary initializer_list is moved into the variable representing the parameter that the constructor takes by value, which [shouldn't] mean all of it's elements are also moved.

Step 5: 4 objects are constructed. 4 destructors are called. Most of your constructors are not logically correct or the message in the destructors would probably be more informative (although I would expect logging this would be more useful than n.)

Edit: Btw, #include <string> , shouldn't.
Last edited on Jun 3, 2016 at 1:31pm
Jun 3, 2016 at 1:27pm
Only one copy ctor is mandated per initializer_list element (from a to the backing array of std::initializer_list)

clang only calls that constructor: http://coliru.stacked-crooked.com/a/fc6a3e0705de519b (I had to make a 2-element list since single-element lists do not use std::initializer_list in C++ any more)

It appears that you're using gcc. A guess at what gcc does wrong was posted on stack overflow a couple years ago: http://stackoverflow.com/a/24753189
Last edited on Jun 3, 2016 at 1:43pm
Jun 3, 2016 at 1:55pm
Okay I've touched a critical side of the language.

I can't blow my mind up just because a compiler has bugs. Stroustrup doesn't tell anyone which compiler he uses but I NEED to know which one is the most standardized.

I can't learn/develop in C++ if I have bugged compilers all over the place.

I use VC++ on Windows, and I have never had any problems.

As I can see, GCC sucks too.

Is clang the best option when I'm not on Windows?
Last edited on Jun 3, 2016 at 1:56pm
Jun 3, 2016 at 2:12pm
Stroustrup doesn't tell anyone which compiler he uses

He mentioned on reddit recently: https://www.reddit.com/r/Denmark/comments/41ud0w/jeg_er_bjarne_stroustrup_datalog_designer_af_c/cz55rco

I can't learn/develop in C++ if I have bugged compilers all over the place.

Compilers are programs too, they have bugs. If you spot one, report it to help others.

There aren't compiler bugs in this example though. There is a language specification bug (single-element initializer list calling the std::initializer_list constructor) and a quality of implementation issue (gcc moving your objects more times than necessary).

And yes, if you really like to be pedantic, clang has had the best track record on implementing latest updates to the language standard; see their status page: core http://clang.llvm.org/cxx_status.html#cxx17 library: http://libcxx.llvm.org/cxx1z_status.html
Jun 3, 2016 at 2:25pm
If you see http://coliru.stacked-crooked.com/a/882e2ab84b18c884 either if I use the -fno-elide-constructors or not, the result is the same (you can try) with Clang

On GCC, the result changes:

copy elision OFF (here we can see how gcc is sucking...)
1
2
3
4
5
6
7
8
9
10
11
12
ctor (Hello)
copy ctor (Hello)
move ctor (moving Hello copy inside )
copy ctor (Hello)
move ctor (moving Hello copy inside )
initializer list
Destructor of
Destructor of
Destructor of Hello copy
Destructor of Hello copy
Destructor of  ilist
Destructor of Hello


copy elision ON (here it's identical to clang's output)
1
2
3
4
5
6
7
8
ctor (Hello)
copy ctor (Hello)
copy ctor (Hello)
initializer list
Destructor of Hello copy
Destructor of Hello copy
Destructor of Hello copy ilist
Destructor of Hello


This is what I get on VisualC++ compiler (with copy elision ON) = identical to Clang and GCC

1
2
3
4
5
6
7
8
ctor (Hello)
copy ctor (Hello)
copy ctor (Hello)
initializer list
Destructor of Hello copy
Destructor of Hello copy
Destructor of Hello copy ilist
Destructor of Hello


I think VC++ on Windows and Clang everywhere else is the perfect pair.

What do you think?
Jun 3, 2016 at 2:38pm
I think VC++ on Windows and Clang everywhere else is the perfect pair.
What do you think?

I think the choice of the compiler depends on what you need it for.

At a previous job, my programs ran on p795s, T5s and Itaniums, so I used IBM XL C++, Oracle Studio, and HP aCC (with a pass in Clang for warnings/static analysis). Today, I mostly run on intel servers, so the main compilers in use are intel, gcc, and msvc, with, again, clang for syntax checking.
Jun 3, 2016 at 2:39pm
I think the choice of the compiler depends on what you need it for.


I need it for learning the most Standard C++ as possible.


Jun 3, 2016 at 2:40pm
When an actual initialiser list is present, the GNU compiler (current version) without the dubious
-fno-elide-constructors behaves sensibly.
1
2
3
4
5
6
int main()
{
   Foo a("Hello");

   Foo b{ a, a };
}

-------- clang++/libc++ ------------

ctor (Hello)
copy ctor (copying Hello)
copy ctor (copying Hello)
initializer list
Destructor of 
Destructor of 
Destructor of 
Destructor of Hello

--------- g++/libstdc++ ------------

ctor (Hello)
copy ctor (copying Hello)
copy ctor (copying Hello)
initializer list
Destructor of 
Destructor of 
Destructor of 
Destructor of Hello

http://coliru.stacked-crooked.com/a/6ef43e056948b69e

However, the GNU compiler is non-conforming when no initialiser list is involved.
1
2
3
4
5
6
int main()
{
   Foo a("Hello");

   Foo b{ a };
}

-------- clang++/libc++ ------------

ctor (Hello)
copy ctor (copying Hello)
Destructor of 
Destructor of Hello

--------- g++/libstdc++ ------------

ctor (Hello)
copy ctor (copying Hello)
initializer list
Destructor of 
Destructor of 
Destructor of Hello

http://coliru.stacked-crooked.com/a/11f6e191e1c559ff

Microsoft is fine: http://rextester.com/AXHX93235
Last edited on Jun 3, 2016 at 2:43pm
Jun 3, 2016 at 2:57pm
I need it for learning the most Standard C++ as possible.

clang with libc++ is probably the best bet, then. (on coliru, use -stdlib=libc++). Clang's lead developer is also the current C++ standard's project editor, and libc++'s lead developer invented move semantics, unique_ptr, and other important parts of C++11
Topic archived. No new replies allowed.