C++ class 实例未初始化但没有编译错误,为什么

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

我的问题是关于以下代码:

#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;
}

如果我注释掉(1),编译成功。如果取消注释 (1),则会发生编译错误,例如在 VS2017 中它抱怨 "using an unintialized local variable 'a'".

在搜索引擎上搜索了一段时间,目前只知道编译器会自动帮我定义默认构造函数的4种情况:

  1. 一个class成员是一个class(比如B)的一个实例,并且classB已经定义了默认构造函数

  2. 一个class派生自另一个class(比如B),B定义了默认构造函数

  3. a class 有虚函数

  4. 前面3个案例的任意组合。

我很好奇,如果我注释掉 (1),编译器是否会为 class Blob 添加构造函数的定义?

其实跟注释不注释没有关系a.hello();Blob总有一个generated default constructor,否则Blob a;编译不了。

(强调我的)

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.

因此,a.agedefault-initialized 不确定值,任何对其的访问(如 cout << a.age;)都会导致 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.

这取决于您的意图;作为解决方法,您可以添加用户定义的默认构造函数。

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

这里有2个点。

首先是未定义行为问题。由于您没有初始化年龄,它包含一个不确定的值,如果您使用它会导致 UB(有关更多详细信息,请参阅 songyuanyao 的答案)。添加额外的指令不会改变这一点。

接下来是编译器消息。编译器不需要发出任何面向 UB 的警告。如果仅在一种情况下引发错误,则您的并不是特别一致,但程序员应该永远不会编写 UB。所以你真的不能责怪编译器没有发出警告。

TL/DR:不要期望 C++ 编译器在您编写错误代码时总是发出警告。没有警告是必要条件,但不是充分条件。