4

In this example I have two classes: Test and Test2. Both of their constructors erroneously initialze member variable "val_" from itself, rather than from parameter "val" as intended. The difference is that Test initializes using {} syntax whereas Test2 initializes using () syntax. Only Test2's initialization generates an "initialized with itself" warning.

I'm compiling with -Wall which implies -Winit-from-self. As can be seen from the results printed, both constructors print the wrong value for _val.

909> cat initSelfTest.cc #include <iostream> using namespace std; class Test { public: Test (int val); private: int val_; }; Test::Test (int val) : val_ {val_} { cerr << "Test::Test; val = " << val << "; val_ = " << val_ << "\n"; } class Test2 { public: Test2 (int val); private: int val_; }; Test2::Test2 (int val) : val_ (val_) { cerr << "Test2::Test2; val = " << val << "; val_ = " << val_ << "\n"; } int main (int argc, char **argv) { Test test {781981}; Test2 test2 {781981}; } 910> gcc --version gcc (GCC) 8.2.0 Copyright (C) 2018 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 911> g++ -Wall -o initSelfTest initSelfTest.cc initSelfTest.cc: In constructor ‘Test2::Test2(int)’: initSelfTest.cc:23:1: warning: ‘Test2::val_’ is initialized with itself [-Winit-self] Test2::Test2 (int val) ^~~~~ initSelfTest.cc: In constructor ‘Test::Test(int)’: initSelfTest.cc:12:13: warning: ‘*<unknown>.Test::val_’ is used uninitialized in this function [-Wuninitialized] : val_ {val_} ^~~~ initSelfTest.cc: In constructor ‘Test2::Test2(int)’: initSelfTest.cc:24:13: warning: ‘*<unknown>.Test2::val_’ is used uninitialized in this function [-Wuninitialized] : val_ (val_) ^~~~ 912> ./initSelfTest Test::Test; val = 781981; val_ = 0 Test2::Test2; val = 781981; val_ = 0 913> 
1
  • sidenote: you actually made a good case here for using the same name for the parameter as for the member: Test::Test (int val) : val {val}, no way you can confuse the two ;) Commented Sep 17, 2020 at 14:20

1 Answer 1

1

You are using the value before it has been initialized, thats undefined behavior, no error message required/guaranteed. In general warnings are not mandated by the standard.

For the "why is it UB not an error?" I can only speculate. Consider that there are cases that look very similar, but are completely fine. For example

struct foo { foo& f; }; foo f{f}; 

Only dereferencing would cause a problem, but storing the reference for later use is ok. I can imagine that in general it is impossible for compilers to tell such valid cases apart from the evil ones.

Sign up to request clarification or add additional context in comments.

5 Comments

But I am using -Wall option to gcc, which implies -Winit-self, which as I understand is specifically intended to catch this. And it does for the () initialization syntax but not for the {} syntax.
@DavidCogen compiler warnings is an quality of implementation issue. If a compiler feels like it can drown you in warnings or give you no warnings at all. I understood this question to be about C++, if it is about gcc one would need to study the manual or perhaps even dig into implementation details
Ok so maybe I have the wrong forum? Is this not for gcc/g++ questions? If not I'll pursue this elsewhere.
@DavidCogen no sorry, what I meant is that it is the wrong answer, question is fine. Maybe could be more clear by asking "how do I make gcc generate a warning for this case?"
Ok, I think I'll report as a gcc bug since I'm now convinced that it is.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.