Tom
Tom

Reputation: 19302

C++11: inconsistent warnings for out-of-order instance member initialization

The following code crashes, raising std::bad_alloc or sometimes std::logic_error.

#include <string>

class Crasher {
public:
    Crasher() : value(default_value) {}
private:
    std::string value;
    const std::string default_value = "default is yours";
};


int main(void) {
    Crasher();
}

I believe the reason is that the members are initialized out of order, and when value is being intialized in initializer list, default_value hasn't yet been initialized.

However, I don't get any compiler warnings or errors with -Wall enabled. However if I change value and default_value to a POD type like int, then I get a warning from g++:

$ g++ -Wall crasher.cpp 
crasher2.cpp: In constructor ‘Crasher::Crasher()’:
crasher2.cpp:5:23: warning: ‘*<unknown>.Crasher::default_value’ is used uninitialized in this function [-Wuninitialized]
    5 |     Crasher() : value(default_value) {}
      |              

Why do I not get a warning when the type is std::string? Is this a compiler problem, or a quirk of the language?

Upvotes: 5

Views: 116

Answers (1)

Davis Herring
Davis Herring

Reputation: 39868

Initializing one int from another performs an lvalue-to-rvalue conversion on the source. If that’s uninitialized, the behavior is undefined. Initializing one object of class type from another does not do so—it calls a constructor, which merely binds a reference to the source. That’s not undefined even if the source is out of lifetime, although typical copy constructors will of course exhibit undefined behavior in that case. Whether you get a warning then depends on what analysis the compiler does after any inlining of the constructor. With the default of no optimization, getting no warning is understandable.

Upvotes: 2

Related Questions