简体   繁体   中英

Why does this initialization from itself not generate compiler warning?

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> 

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM