I was playing around with various methods of initialization and evaluating the developer experience they provide for various use cases and their performance impacts. In the process, I wrote two snippets of code, one with direct initialization and one with an initializer list.
Direct:
class C {
public:
char* x;
C() : x(new char[10] {'0','1'}) {}
};
C c;
Initializer list:
#include <utility>
#include <algorithm>
class C {
public:
char* x;
C(std::initializer_list<char> il) {
x = new char[10];
std::copy(il.begin(), il.end(), x);
}
};
C c = {'0','1'};
I was expecting std::initializer_list to generate the same assembly and while I can understand why it might be worse (looks more complex), I would have been asking a very different question here if it was actually worse. Imagine my surprise when I saw that it generates better code with fewer instructions!
Link to godbolt with the above snippets - https://godbolt.org/z/i3XZ_K
Direct:
_GLOBAL__sub_I_c:
sub rsp, 8
mov edi, 10
call operator new[](unsigned long)
mov edx, 12592
mov WORD PTR [rax], dx
mov QWORD PTR [rax+2], 0
mov QWORD PTR c[rip], rax
add rsp, 8
ret
c:
.zero 8
Initializer list:
_GLOBAL__sub_I_c:
sub rsp, 8
mov edi, 10
call operator new[](unsigned long)
mov edx, 12592
mov QWORD PTR c[rip], rax
mov WORD PTR [rax], dx
add rsp, 8
ret
c:
.zero 8
The assembly is pretty much the same except for the extra mov QWORD PTR [rax+2], 0 instruction which on first glance seems like termination of the char array with a null character. However, IIRC only string literals (like "01") are automatically terminated with null char, not char array literals.
Would appreciate any insight into why the generated code is different and anything I can do (if possible) to make the direct case better.
Also, am a noob when it comes to x86 assembly, so let me know if I am missing something obvious.
EDIT: It only gets worse if I add more chars - https://godbolt.org/z/e8Gys_