I agree with the consensus that it's generally best to initialise C++ data members in a member initialization list rather than the body of a constructor, but I am sceptical of this explanation
The other (inefficient) way to build constructors is via assignment, such as:
Fred::Fred() { x_ = whatever; }.
In this case the expression whatever causes a separate, temporary object to be created, and this temporary object is passed into the x_ object’s assignment operator. Then that temporary object is destructed at the;
. That’s inefficient.
Is this actually correct? I would have expected the compiler to elide the default-constructed temporary object which is immediately replaced by assignment in the body. I don't know why I expected this but having read the above claim I guess I have been quietly assuming it for years.
Are member initialization lists actually more efficient? If so, is it for this reason?
Using member init list,
#include <string>
struct Fred {
Fred() : x_("hello") { }
std::string x_;
};
int main() {
Fred fred;
}
Clang 3.9.1 and gcc 6.3 generate the following with -O3 -fno-exceptions
(Compiler Explorer):
main: # @main
xor eax, eax
ret
If we do an assignment in the body instead:
#include <string>
struct Fred {
Fred() { x_ = "hello"; }
std::string x_;
};
int main() {
Fred fred;
}
both generate a lot more code, e.g. Clang 3.9.1 outputs this:
main: # @main
push rbx
sub rsp, 32
lea rbx, [rsp + 16]
mov qword ptr [rsp], rbx
mov qword ptr [rsp + 8], 0
mov byte ptr [rsp + 16], 0
lea rdi, [rsp]
xor esi, esi
xor edx, edx
mov ecx, .L.str
mov r8d, 5
call std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_M_replace(unsigned long, unsigned long, char const*, unsigned long)
mov rdi, qword ptr [rsp]
cmp rdi, rbx
je .LBB0_2
call operator delete(void*)
.LBB0_2:
xor eax, eax
add rsp, 32
pop rbx
ret
.L.str:
.asciz "hello"
So it seems member init lists really are more efficient, at least for some cases, even with modern compilers.