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种情况:
一个class成员是一个class(比如B)的一个实例,并且classB已经定义了默认构造函数
一个class派生自另一个class(比如B),B定义了默认构造函数
a class 有虚函数
前面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.age
是 default-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++ 编译器在您编写错误代码时总是发出警告。没有警告是必要条件,但不是充分条件。
我的问题是关于以下代码:
#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种情况:
一个class成员是一个class(比如B)的一个实例,并且classB已经定义了默认构造函数
一个class派生自另一个class(比如B),B定义了默认构造函数
a class 有虚函数
前面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.age
是 default-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++ 编译器在您编写错误代码时总是发出警告。没有警告是必要条件,但不是充分条件。