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

Community
  • 1
  • 1
meddle0106
  • 1,292
  • 1
  • 11
  • 22
  • What compiler/platform/OS are you using, most compilers have flags that will raise such a warning – EdChum Apr 11 '14 at 08:33
  • @EdChum His live example shows g++4.8 with `-Wall` and `-Wextra` doesn't warn about it. – JBL Apr 11 '14 at 08:34
  • 2
    @JBL adding `-Weffc++` flag will generate: `main.cpp:6:5: warning: 'B::m' should be initialized in the member initialization list [-Weffc++]` – EdChum Apr 11 '14 at 08:37
  • See [live example](http://coliru.stacked-crooked.com/a/a07921cb25ae7313) – EdChum Apr 11 '14 at 08: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. – kcm1700 Apr 11 '14 at 08:40

3 Answers3

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.

Community
  • 1
  • 1
Nawaz
  • 353,942
  • 115
  • 666
  • 851
  • 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 Apr 11 '14 at 08:50
  • @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. – Nawaz Apr 11 '14 at 08:56
  • You are right. It produces a warning. But with example below, warning can be removed and problem still occurs. – meddle0106 Apr 11 '14 at 10:46
1

-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?

k.st.
  • 41
  • 4
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.

Community
  • 1
  • 1
EdChum
  • 376,765
  • 198
  • 813
  • 562
  • Please look at the new edited example http://coliru.stacked-crooked.com/a/6a73542bce79d098 Now, -Weffc emits no warning any more but the problem still occurs. – meddle0106 Apr 11 '14 at 10:39
  • @meddle0106 It should probably catch this but it may be very hard, interestingly `B b = B(b)` generates a different unitialised value see: http://coliru.stacked-crooked.com/a/3022c6cf193e21a0 – EdChum Apr 11 '14 at 10:46