ChrisZZ
ChrisZZ

Reputation: 2181

C++ class instance not initialized but no compile error, why

My question is about the following code:

#include <stdio.h>
#include <iostream>
#include <string>

using namespace std;

class Blob {
public:
    int age;
    void hello() { printf("hello\n"); }
};

void test_case() {
    Blob a;
    //a.hello();         //(1)
    cout << a.age << endl;
}

int main() {
    test_case();
    return 0;
}

if I comment out (1), it compile success. If uncomment out (1), compile error occur, e.g. in VS2017 it complains "using an unintialized local variable 'a'".

I've searched in search engine for a while and now only know the following 4 cases that the compiler will automatically help me define the default constructor:

  1. a class member is an instance of a class (say B), and class B have defined default constructor

  2. a class is derived from another class (say B), and B has defined default constructor

  3. a class has virtual function

  4. any combination of the previous 3 cases.

I'm curious that, if I comment out (1), will the compiler add a definition of constructor for the class Blob?

Upvotes: 1

Views: 595

Answers (2)

songyuanyao
songyuanyao

Reputation: 172964

In fact it has nothing to do with comment out or not a.hello();, Blob always has a generated default constructor, otherwise Blob a; won't compile.

(emphasis mine)

If no user-declared constructors of any kind are provided for a class type (struct, class, or union), the compiler will always declare a default constructor as an inline public member of its class.

If the implicitly-declared default constructor is not defined as deleted, it is defined (that is, a function body is generated and compiled) by the compiler if odr-used, and it has the same effect as a user-defined constructor with empty body and empty initializer list.

As the result, a.age is default-initialized to indeterminate value, any access to it (like cout << a.age;) leads to UB.

3) when a base class or a non-static data member is not mentioned in a constructor initializer list and that constructor is called.

otherwise, nothing is done: the objects with automatic storage duration (and their subobjects) are initialized to indeterminate values.

It depends on your intent; as the workaround you can add a user-defined default constructor.

class Blob {
public:
    int age;
    void hello() { printf("hello\n"); }
    Blob() : age(42) {}
};

Upvotes: 3

Serge Ballesta
Serge Ballesta

Reputation: 149075

There are 2 points here.

First is the Undefined Behaviour question. As you do not initialize age, it contains an indeterminate value which leads to UB if you use it (see songyuanyao's answers for more details on that). Adding an additional instruction does not change anything to that point.

Next is the compiler message. Compilers are not required to issue any warning facing UB. Yours is not specially consistent if it raises the error in only one case, but the programmer is supposed to never write UB. So you cannot really blame the compiler for not issuing the warning.

TL/DR: do not expect a C++ compiler to alway issue warning when you write incorrect code. Having no warning is a necessary condition, but not a sufficient one.

Upvotes: 1

Related Questions