0

This question may turn out to be more about CPUs/memory than the C++ language itself.

I have a class B provided below.

class B {
public:
    B(int num): num_(num), a(num_){}

private:
    int num_;
    A a;
};

In the constructor of B, the object a is initialized with num_ rather than num. I could instead have written this class B_Alternative.

class B_Alternative {
public:
    B_Alternative(int num) : num_(num), a(num) {}

private:
    int num_;
    A a;
};

Which is faster? My understanding is that the answer may depend on where B is stored. If B is on the stack, then the compiler will likely retrieve num_ from B directly and there is no speed loss. If B is on the heap, then a stack frame will need to be made to construct a, and a copy of num_ will be moved to the stack to run A's constructor. Then num_ will be moved back to the heap in the position of a. This will result in the constructor of B being slower than the constructor of B_Alternative regardless of where B_Alternative is stored.

An example A is included below. This is just an example.

class A {
public:
    A(int num) : num_(num) {}
private:
    int num_;
};
mana
  • 545
  • 4
  • 12
  • 2
    You will be surprised to learn that modern C++ compilers will (at the medium optimization level) generate identical code. In the unlikely event otherwise it will be impossible to tell the difference on modern multi-ghz CPUS. – Sam Varshavchik Jun 27 '21 at 12:16
  • 2
    You lack definition of A that is needed to answer that. If it takes mutable reference to its constructor argument and mutates it then the behavior of those two classes is very different. – Öö Tiib Jun 27 '21 at 12:16
  • 1
    @Eljay It's the other way round: `B_Alternative` is safe, `B` depends on the order of members. – Igor Tandetnik Jun 27 '21 at 12:26
  • @IgorTandetnik • Yes, oops. Shouldn't reply until I've had my coffee. – Eljay Jun 27 '21 at 12:41
  • @mana The question does not make a sense. You should use this mem-initializer list B_Alternative(int num) : num_(num), a(num) because it does not depend on the order of data member declarations and as a result is safer. – Vlad from Moscow Jun 27 '21 at 12:58
  • Nothing is moved between the stack and heap in B_alternative. It is constructed in-place on the heap. – Raymond Chen Jun 27 '21 at 13:05
  • @VladfromMoscow if ```a(num_)``` is the conceptually "correct" version, then it is "safer" against changes to how ```num_``` is initialized. For example, if the initialization is changed to ```num_(num+1)``` then ```B``` will still be correct. Regardless, this question is about how the machine performs the two options differently. – mana Jun 27 '21 at 13:46
  • @mana In case you are not aware: initialization of data members is performed in the order they are listed in the class definition - not the order they appear in the member initializer list. If someone later swaps `int num_;` and `A a;` in the class definition, `a(num_)` will happen before `num_(num)` - whereupon the program will exhibit undefined behavior by way of accessing an uninitialized object. For this reason, one must be very careful when initializing members from other members. If that is necessary, at least add a comment near the declarations, explaining that the order is significant. – Igor Tandetnik Jun 27 '21 at 15:34
  • As to "how the machine performs the two options" - you could write a test and look at the generated assembly. I expect the two versions to produce identical machine code with any mainstream modern compiler. – Igor Tandetnik Jun 27 '21 at 15:41

0 Answers0