枚举值超出范围 class
The out of range value of enum class
当我在一个函数中定义一个 enum class
时,它有一个来自可用选项的值。但是,当我在 class 中定义它时,它具有 none 个选项的值。那么g.f
的初始值是多少呢?比较时 return true
会是什么? ((g.f==??)==true)
?
#include <iostream>
enum class Fruit
{
apple,
orange
};
class Garden
{
public:
Fruit f;
};
void print_enum(Fruit f)
{
switch(f)
{
case Fruit::apple:
std::cout<<"apple\n";
break;
case Fruit::orange:
std::cout<<"orange\n";
break;
default:
std::cout<<"other\n";
break;
}
}
int main()
{
Garden g;
Fruit f;
print_enum(f); // apple
print_enum(g.f); // other
return 0;
}
始终初始化您的变量,C++ 在某些情况下不会使用 "default" 值初始化它们。
在这两种情况下你都写在这里你是在你的编译器和 OS 的摆布下,但你可能会在你的 enum
变量中得到 garbage
(那是您在后一种情况下进行的实验)。如果你想看看 garbage
是什么,执行这个:
std::cout << (int)g.f << std::endl;
标准规定访问自动存储持续时间的未初始化变量的值会产生未定义的行为。
结果是任何依赖于访问该值的操作都会产生未定义的行为。访问变量的值是必要的;
- 将它与另一个值进行比较。例如,如果
a
或 b
未初始化,则 a == b
给出未定义的行为。如果 a
未初始化,即使比较 a == a
也会给出未定义的行为。
- 将值赋给另一个变量。例如,如果
b
未初始化,a = b
会给出未定义的行为。
- 按值将其传递给函数。对于函数
f()
,如果 a
未初始化,调用 f(a)
将给出未定义的行为。
- 输出值。例如,如果
a
未初始化,std::cout << a
会给出未定义的行为。
因此,要求未初始化的变量具有特定值是没有意义的。访问该值会产生未定义的行为,因此测试它是否等于(或不等于、大于或......)任何值都会产生未定义的行为。
这通常通过将未初始化变量的值描述为不确定来概括。如果在不引入未定义行为的情况下无法访问值,则无法可靠地确定该值是什么。
当然,还有一个问题,即为什么标准认为访问未初始化变量的值会产生未定义的行为。保留未初始化的值允许编译器为变量分配内存(例如从堆栈),但不必费心初始化它 - 该内存中的数据可以是恰好存在的任何数据。将变量初始化为任何指定值可能是一项昂贵的操作(例如,一个包含 200 万个元素的数组是一个变量,尽管它很大,并且初始化它可能在计算上很昂贵)。这通常也是不必要的操作,因为许多代码对初始化变量所做的第一件事是(等待它......)为其赋值,即初始化它。
(可能)既不必要又浪费计算的操作往往不受程序员和编译器供应商的欢迎。使行为未定义会消除所有这些......尽管要求程序员在访问变量值的任何操作之前小心初始化变量。
当我在一个函数中定义一个 enum class
时,它有一个来自可用选项的值。但是,当我在 class 中定义它时,它具有 none 个选项的值。那么g.f
的初始值是多少呢?比较时 return true
会是什么? ((g.f==??)==true)
?
#include <iostream>
enum class Fruit
{
apple,
orange
};
class Garden
{
public:
Fruit f;
};
void print_enum(Fruit f)
{
switch(f)
{
case Fruit::apple:
std::cout<<"apple\n";
break;
case Fruit::orange:
std::cout<<"orange\n";
break;
default:
std::cout<<"other\n";
break;
}
}
int main()
{
Garden g;
Fruit f;
print_enum(f); // apple
print_enum(g.f); // other
return 0;
}
始终初始化您的变量,C++ 在某些情况下不会使用 "default" 值初始化它们。
在这两种情况下你都写在这里你是在你的编译器和 OS 的摆布下,但你可能会在你的 enum
变量中得到 garbage
(那是您在后一种情况下进行的实验)。如果你想看看 garbage
是什么,执行这个:
std::cout << (int)g.f << std::endl;
标准规定访问自动存储持续时间的未初始化变量的值会产生未定义的行为。
结果是任何依赖于访问该值的操作都会产生未定义的行为。访问变量的值是必要的;
- 将它与另一个值进行比较。例如,如果
a
或b
未初始化,则a == b
给出未定义的行为。如果a
未初始化,即使比较a == a
也会给出未定义的行为。 - 将值赋给另一个变量。例如,如果
b
未初始化,a = b
会给出未定义的行为。 - 按值将其传递给函数。对于函数
f()
,如果a
未初始化,调用f(a)
将给出未定义的行为。 - 输出值。例如,如果
a
未初始化,std::cout << a
会给出未定义的行为。
因此,要求未初始化的变量具有特定值是没有意义的。访问该值会产生未定义的行为,因此测试它是否等于(或不等于、大于或......)任何值都会产生未定义的行为。
这通常通过将未初始化变量的值描述为不确定来概括。如果在不引入未定义行为的情况下无法访问值,则无法可靠地确定该值是什么。
当然,还有一个问题,即为什么标准认为访问未初始化变量的值会产生未定义的行为。保留未初始化的值允许编译器为变量分配内存(例如从堆栈),但不必费心初始化它 - 该内存中的数据可以是恰好存在的任何数据。将变量初始化为任何指定值可能是一项昂贵的操作(例如,一个包含 200 万个元素的数组是一个变量,尽管它很大,并且初始化它可能在计算上很昂贵)。这通常也是不必要的操作,因为许多代码对初始化变量所做的第一件事是(等待它......)为其赋值,即初始化它。
(可能)既不必要又浪费计算的操作往往不受程序员和编译器供应商的欢迎。使行为未定义会消除所有这些......尽管要求程序员在访问变量值的任何操作之前小心初始化变量。