views:

107

answers:

5

I had a nasty experience with C++ initialization, and I'm trying to see whether there is a real-world example which justifies no warnings from the compiler.

The following code compiles correctly, but foo and bar get initialized with uninit values (I assume from the uninitialized parent class). The compilers, both g++ and VS, don't emit any warnings. I have been told of course that it is bad behavior to leave members public and don't decorate them. However, I assume the compiler could spot this kind of inconsistency and at least issue a warning at the highest warning levels, because I can't see any application of this kind of code.

#include <iostream>
using namespace std;

class base_class {
    public:
        int foo;
        int bar;

    base_class(int foo,int bar):
        foo(foo),bar(bar) 
    {}
};

class derived_class: public base_class {
    public:
    derived_class(int Foo, int Bar):
        base_class(foo,bar)
    { 
                    int a = Foo * Bar;

                    a++;
                    cout << foo << " " << bar << endl;
    }
};

int main ()
{
    derived_class *buzz = new derived_class(1,2);
    buzz->print();
}
A: 

I think your problem is that you have your constructor parameters with capital letters :

With the following code, I get the right values :

#include <iostream>
using namespace std;

class base_class {
    public:
        int foo;
        int bar;

    base_class(int foo,int bar):
        foo(foo),bar(bar)
        {
        int a = foo * bar;

        a++;

        cout << "Base : " << foo << ", " << bar << ", " << a << endl;
    }

};

class derived_class: public base_class {
    public:
    derived_class(int foo, int bar):
        base_class(foo,bar)
    {
        cout << "derived : " << foo << ", " << bar << endl;
    }
};

int main ()
{
    derived_class baz(1,2);
}

Output :

Base : 1, 2, 3
derived : 1, 2

What happens then is that your members are "initialized" with your uninitialized members values :)

my2c

neuro
I dont think so. If that is the case, it should have resulted in a compiler error. But he meant that it compiles. May be he missed out while typing in the question here.
liaK
@liak: The base class constructor does not compile. When you correct the typo (foo * bar) it compiles but with unitialized values. I think there was two typo at first one was corrected to make the code compile, and then He gets the uninitialized values ... @Metiu : Am I right ? If not give us the whole exact compiling code ...
neuro
A: 

This:

#include <iostream>

class base_class {
public:
    int foo;
    int bar;
    base_class(int foo,int bar) : foo(foo),bar(bar) {}
};

class derived_class : public base_class {
public:
    derived_class(int foo, int bar) : base_class(foo,bar) {}
};

int main ()
{
    derived_class baz(1,2);
    std::cout << baz.foo << ", " << baz.bar << '\n';
    return 0;
}

compiles fine for me using VC9 and VC10 and writes 1, 2 in both cases. Do you get anything else?

Note, however, that naming both your member variables and constructor parameters the same is bound to create confusion.

Standard disclaimer: Except for silly examples like this, never use public data.

sbi
See the latest revision of the code, which fixed the typos
Metiu
@Metiu: And why should __I__ go back to your code and try to find whatever you have changed? It's not me who wants something, it's you. So please take the time to explain what you changed and why, and how that's relevant to my answer. BTW, my answer asked you whether you get the same result for my code (implying that you look at the differences between mine and yours if it does). You still haven't responded to that.
sbi
A: 

The analysis needed to warn about the use of uninitialised variables at compile time is quite complex, and it seems that GCC only does it when optimisation is enabled. Presumably someone thought it slowed down a non-optimising build unacceptably.

Compiling your code with g++ -Wall -O does give warnings. I can't comment on Visual Studio.

Mike Seymour
See Revision 7 of the code: that doesn't give warnings even with -O3 -pedantic -W -Wall, just by using new instead of static initialization
Metiu
@Metiu: I'm fairly sure it's impossible for static analysis to guarantee that it can find any conceivable use of uninitialised variables, so the compiler has to draw the line somewhere. However cunning the compiler is, you'll always be able to contrive an example where it fails. On the other hand, a run-time analysis tool such as Valgrind will find the problem, as long as the code is executed at some point during its analysis.
Mike Seymour
A: 

Your updated code reveals your problem:

In line 17 you use foo and bar from base_class to call the constructor of base_class with values that haven't been initiliazed by then. The result is undefined behaviour and thus the strange values. As Mike said: You get a warning only with optimisation turned on which is quite strange.

pmr
Yes I suspected that was the reason for the error, and of course I can program defensively, but see Revision 7 which, using a pointer, doesn't even give any warnings with -O3.
Metiu
A: 

I think you are not compiling with all warnings activated (and you really should). For example, on your code, here is the output from g++:

g++ -O3 -W -Wall    init.cc   -o init
init.cc: In function ‘int main()’:
init.cc:22: warning: ‘baz.derived_class::<anonymous>.base_class::foo’ is used uninitialized in this function
init.cc:28: note: ‘baz.derived_class::<anonymous>.base_class::foo’ was declared here
init.cc:22: warning: ‘baz.derived_class::<anonymous>.base_class::bar’ is used uninitialized in this function
init.cc:28: note: ‘baz.derived_class::<anonymous>.base_class::bar’ was declared here

You will notice the -W -Wall to ensure maximum warnings. Otherwise, as pointed before, the error is in the case used for the variable initialization.

PierreBdR
@PierreBdR: Yes you're right, albeit it works only with -O, without optimizations it won't work.Please look at my Revision 7 example, which doesn't give any warning.
Metiu