3

Driven from my last question Initialisation of static variable with itself, lets consider following new example:

#include <iostream> class B { public: B() { std::cout << "B()" << std::endl; m = 17; } B(const B & o) { std::cout << "B(const B& o)" << std::endl; m = o.m; } B & operator=(const B & o) { std::cout << "B & operator=(const B & o)" << std::endl; m = o.m; return *this; } int m; }; int main() { B b = b; std::cout << b.m << std::endl; } 

The output of the program is

B(const B& o) 1840828080 

'b' is used uninitialised here because it is used in copy constructor to construct itself. It leads to the uninitialised variable 'm', thus showing garbage. Why does the compiler do not warn here, that 'b' is used uninitialised (while 'int a = a' produces such a warning).

Link to live example

5
  • What compiler/platform/OS are you using, most compilers have flags that will raise such a warning Commented Apr 11, 2014 at 8:33
  • @EdChum His live example shows g++4.8 with -Wall and -Wextra doesn't warn about it. Commented Apr 11, 2014 at 8:34
  • 2
    @JBL adding -Weffc++ flag will generate: main.cpp:6:5: warning: 'B::m' should be initialized in the member initialization list [-Weffc++] Commented Apr 11, 2014 at 8:37
  • See live example Commented Apr 11, 2014 at 8:38
  • 3
    The compiler is not responsible for reporting warnings for all cases, it's not even possible. The compiler just try to do its best to detect the cases. Commented Apr 11, 2014 at 8:40

3 Answers 3

3

Because it is undefined behaviour, the compiler may or may not give any warning! It is not a requirement on the compilers to give diagnostics (warnings/errors) in such cases.

And your code invokes undefined behaviour, because b (on the right side of =) is uninitialized (as you know yourself) — reading its value invokes UB. It is fundamentally the same case as this one.

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

3 Comments

Of course it is no requirement for the compiler to warn. I was just wondering, why a warning occurs for primitive int but not for a class. (For the same warning level). '-weffc++' was the answer...
@meddle0106: I'm wondering how -weffc++ is the answer. Yes, it makes the compiler produce warning, but still it doesn't answer "why a warning occurs for primitive int but not for a class" because I'm sure you didn't use -weffc++ with primitive int. To know the answer (i.e the reason for the difference), you've to look into the source code of GCC.
You are right. It produces a warning. But with example below, warning can be removed and problem still occurs.
2

-Weffc++ is definitely not the answer! The warning just says, that the initialization should go to initialization list. If You do that, the warning disappears:

#include <iostream> class B { public: B() : m(17) { std::cout << "B()" << std::endl; } B(const B & o) : m(o.m) { std::cout << "B(const B& o)" << std::endl; } B & operator=(const B & o) { std::cout << "B & operator=(const B & o)" << std::endl; m = o.m; return *this; } int m; }; int main() { B b = b; int i = i; std::cout << b.m << " " << i << std::endl; } 

The compiler at the live example gives a warning for the simple variable i, but not for the class variable b. So the question remains unanswered - Why does the compiler warn for a simple type, but not for a more complex one?

Comments

0

As @Nawaz has stated and @kcm1700 warnings are not a requirement for the compiler.

As to why this flag -weffc++ seems to be more strict than -Wall -Wextra -pedantic see the online docs: http://gcc.gnu.org/onlinedocs/gcc/C_002b_002b-Dialect-Options.html.

You can see from the docs:

The following -W... options are not affected by -Wall.

-Weffc++ (C++ and Objective-C++ only) Warn about violations of the following style guidelines from Scott Meyers' Effective C++ series of books: Define a copy constructor and an assignment operator for classes with dynamically-allocated memory. Prefer initialization to assignment in constructors. Have operator= return a reference to *this. Don't try to return a reference when you must return an object. Distinguish between prefix and postfix forms of increment and decrement operators. Never overload &&, ||, or ,. This option also enables -Wnon-virtual-dtor, which is also one of the effective C++ recommendations. However, the check is extended to warn about the lack of virtual destructor in accessible non-polymorphic bases classes too.

When selecting this option, be aware that the standard library headers do not obey all of these guidelines; use ‘grep -v’ to filter out those warnings.

So if you add the -weffc++ flag then it will generate the desired warning:

g++-4.8 -std=c++11 -Weffc++ -Wall -Wextra -pedantic main.cpp && ./a.out main.cpp: In constructor 'B::B()': main.cpp:6:5: warning: 'B::m' should be initialized in the member initialization list [-Weffc++] B() ^ main.cpp: In copy constructor 'B::B(const B&)': main.cpp:12:5: warning: 'B::m' should be initialized in the member initialization list [-Weffc++] B(const B & o) ^ 

See live example and related:Easy way find uninitialized member variables

For your modified examples in the comments, clang detects both correctly, see this: http://coliru.stacked-crooked.com/a/d1a55f347ee928be and http://coliru.stacked-crooked.com/a/9676797c7d155b81

The output is:

main.cpp:27:12: warning: variable 'b' is uninitialized when used within its own initialization [-Wuninitialized] B b = b; ~ ^ 1 warning generated. 

Different compilers will have different competencies with respect to detecting such problems.

2 Comments

Please look at the new edited example coliru.stacked-crooked.com/a/6a73542bce79d098 Now, -Weffc emits no warning any more but the problem still occurs.
@meddle0106 It should probably catch this but it may be very hard, interestingly B b = B(b) generates a different unitialised value see: coliru.stacked-crooked.com/a/3022c6cf193e21a0

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.