0

The following code, as far as I can tell, correctly initializes the variables of the derived class B:

#include <utility>

struct A {
  int i;
};

struct B : A {
  int j;
  explicit B(A&& a) : A(std::move(a)), j{i} { }
};

int main()
{
  A a{3};
  B b(std::move(a));

  return 0;
}

Running cppcheck with --enable=all gives the warning:

[test.cpp:9]: (warning) Member variable 'A::i' is not initialized in the constructor. Maybe it should be initialized directly in the class A?

Is there a reason for this (false, I think) warning?

francesco
  • 7,189
  • 7
  • 22
  • 49
  • 2
    Why do you think A::i is properly initialized as your warning suggests? – Captain Giraffe Apr 27 '22 at 14:51
  • @CaptainGiraffe I assume A has the default move/copy constructors, which in fact is used in the main(). – francesco Apr 27 '22 at 14:55
  • A::i will sit in an undefined state. – Captain Giraffe Apr 27 '22 at 14:56
  • @CaptainGiraffe Did you make a typo in your first comment? You wrote: *"Why do you think A::i is properly initialized"* **instead of** *"Why do you think A::i is not properly initialized"* – Jason Apr 27 '22 at 14:57
  • @CaptainGiraffe Why do you think `A::i` is not initialized in `B` constructor? Note that cppcheck doesn't refer to general case for `A::i`, but to the specific use on line 9. – Yksisarvinen Apr 27 '22 at 14:58
  • 1
    `A` would get a default constructor with that error. But that constructor is never called. Not sure, why it shows the error for line 9. – Sebastian Apr 27 '22 at 15:40

1 Answers1

3

Yes, this looks like a false positive. Base class subobjects are initialized before direct member subobjects and A(std::move(a)) will use the implicit move constructor which initializes this->i with a.i, so this->i will be initialized before the initialization of this->j is performed (which reads this->i).

The argument given to the constructor in main is also completely initialized via aggregate initialization, so a.i's value will not be indeterminate either.

user17732522
  • 53,019
  • 2
  • 56
  • 105
  • Thanks! It appears that cppcheck warns that I *may* improperly initialize A, although I believe it is sensible to assume, in the constructor of B, that the parameter is correctly initialized... Interestingly, if you add ```A()=delete;``` to A, the warning disappears. – francesco Apr 27 '22 at 15:09
  • @francesco As far as I know cppcheck doesn't actually fully parse C++ syntax and interpret its semantics, like e.g. Clang's or GCC's static analyzer would. Instead it often uses looser pattern rules. It might not actually be performing the overload resolution (correctly) and may instead (incorrectly) reason that lack of an user-declared constructor in `A` means that `i` cannot be initialized. – user17732522 Apr 27 '22 at 15:20