1

Let's say I have the following code

class C {
public:
  explicit C() :
     member()
  {}
private:
  int member;
};

I suppose member() value-initializes my member variabile to zero.

My question is: does this have any overhead at runtime? Or is it done in some particular way at compile time?

Dean
  • 6,610
  • 6
  • 40
  • 90
  • This is related:, but not a duplicate: https://stackoverflow.com/questions/44678277/constexpr-for-creating-objects – Bathsheba Jun 27 '18 at 07:13
  • Possible duplicate of [Performance issues when initializing each class member?](https://stackoverflow.com/questions/48866872/performance-issues-when-initializing-each-class-member) – Peter VARGA Jun 27 '18 at 07:47

2 Answers2

5

In short: There is a small overhead but the compiler is smart!

The long version:

The memory has to be zeroed out and that takes a bit of work. You can see that when you compile your class to assembly, together with a simple driver function

int main() { C c; } 

using -O1 optimizations.

Then without the member initialization, the generated code looks like

main: # @main
  push rax
  mov rdi, rsp
  call C::C() [base object constructor]
  xor eax, eax
  pop rcx
  ret
C::C() [base object constructor]: # @C::C() [base object constructor]
  ret

Where in the last two lines you see that the constructor is trivial. When you add the member initialization with the brackets, it becomes

C::C() [base object constructor]: # @C::C() [base object constructor]
  mov qword ptr [rdi], 0
  ret

The mov instruction is setting a DWORD at some specific memory location to zero. DWORD is 32-bits.

The compiler may be able to combine initializations. For example, if you add a second int:

class C {
public:
  explicit C()
     : member(), anotherMember()     
  {}
private:
  int member;
  int anotherMember; // <====
};

int main() {
    C c;
}

then the DWORD changes to a QWORD so it actually zeroes both integers at once. You will see this even with a higher optimization level, for example when you add something the compiler cannot optimize away such as a read from stdin and compile this with -O2

#include <iostream> 

class C {
public:
  explicit C()
     : member()
  {}
  int member;
};

int main() {
    int x;
    C c;
    std::cin >> c.member;
}

then the constructor body will be inlined into the main function but you will still find the zero-instruction

mov dword ptr [rsp], 0

Also note that depending on the code following the instantiation, the compiler may optimize further. For example, if you look at the output for

C c;
c.member = expression;

then you will see that the zero-assignment will be removed from the output.

CompuChip
  • 9,143
  • 4
  • 24
  • 48
  • What was so **TL;DR:** about the 3-sentences in the question that you couldn't take the time to read before posting an answer. **TL;DR:** adds nothing to your answer other than a qualification that "My answer might not be right because I didn't take time to read the question." -- and it just looks childish. So please, in the future, avoid the over use of cute acronyms in your answers. (other than that nit, Nice Answer) – David C. Rankin Jun 27 '18 at 07:45
  • @DavidC.Rankin the TL;DR is not about the question but my answer: it is quite long and detailed so if you don't want to read all of it the "TL;DR" summarizes the conclusion. I will remove the confusing acronym :-) – CompuChip Jun 27 '18 at 08:15
  • @CompuChip - I would hesitate to put the **Yes** in bold when it comes down to a single machine instruction. Especially when you also show that you get a discount when initializing multiple variables. :-) In a (moderately good) [question the other day](https://stackoverflow.com/a/51009508/597607) we noticed that a loop with two operations had the same cost as a loop with only one line of code. An instruction can be "free" in some contexts. – Bo Persson Jun 27 '18 at 11:32
2

It depends on the compiler and its optimization. Let's assume the optimization level is none, then the compiler will most probably generate some instructions for init the member variable. This code is optimized out e.g. for gcc when using -O1.

Compare the differences between member initialization and without:
https://godbolt.org/g/ZE62PP vs https://godbolt.org/g/msRQtp

rbf
  • 541
  • 4
  • 16