我想问为什么使用未初始化的变量被认为是非类型安全的?
我正在从该站点上的C ++书籍指南中阅读Bjarne Stroustrup的初学者书籍(使用C ++进行编程的原理和实践)。
该书中有关类型安全的部分内容指出:
当对象是对象时,程序(或程序的一部分)是类型安全的 仅根据其类型的规则使用。例如,使用 变量在初始化之前不被视为类型安全。
然后,本书提供以下代码作为示例:
int main() {
double x; // we "forgot" to initialize
// the value of x is undefined
double y = x; // the value of y is undefined
double z = 2.0+x; // the meaning of + and the value of z are undefined
}
我了解未初始化的局部变量将具有 不确定的值,读取此变量将导致未定义的行为。我不明白的是它如何连接到类型安全。我们仍然可以从变量的定义中了解类型。
为什么上面的代码中的注释指出当2.0和x均为double时,+的含义未定义,而对double + double定义了+?
答案 0 :(得分:2)
Undefined behavior表示输出可能是您期望的结果,或者某些不确定的值,该值可能超出类型的有效范围。
一个明确的未定义行为示例是signed integer overflow:
unsigned int i; // uninitialized
int x = i + 2; // indeterminate value
if (x + 1 > x) {} // undefined behavior due to signed overflow
如果x
的最大值为int
,则 i
的值可以超出有效范围unsigned int
。
因此,对于具有不确定值的表达式,不能保证类型安全。
答案 1 :(得分:2)
@codekaizer和@Shankar是正确的:根据定义,未定义的行为不是安全行为。但是,如何将其应用于原始类型会更困难。合理的做法是,任何适当长的位序列都可以是有效的int
。正如@BoPersson在下面指出的那样,这是not strictly true,实现可以自由地包含在算术下导致interrupts的值。对于整数,当用于除数时,这实际上仅适用于0,但这并不意味着该标准不允许在不适当的体系结构上使用诸如浮点NaN
之类的整数版本。
读者可能会发现一个带有虚拟功能的示例,可以更直观地说明为什么未初始化的变量类型不安全。考虑:
struct Base {
virtual int foo() const =0;
};
struct DerivedA : public Base {
int foo() const override { return 10; }
};
struct DerivedB : public Base {
int foo() const override { return -10; }
};
int main() {
Base* abstractStructPtr;
std::cout << abstractStructPtr->foo() << std::endl;
return 0;
}
abstractStructPtr
的类型意味着您可以在其上调用foo()
。该表达式有效:abstractStructPtr
有一个类型,这就是为什么您可以调用foo()
的原因。但是,foo()
的实现存在于派生类中。
由于abstractStructPtr
未初始化,因此不能保证指向的数据可以完成对foo()
的调用。换句话说,尽管absractStructPtr
的类型为Base*
,但不能保证所指向的数据实际上是任何类型的Base
对象。因此,调用foo()
是未定义的行为,也不安全。什么事情都可能发生;实际上,它可能只是由于内存访问冲突而崩溃,但事实并非如此! Kablooey。
答案 2 :(得分:0)
即使'x'被声明为双精度,由于未初始化,它在内存中具有随机位模式,该模式可能不表示任何有效的双精度数字。因此,“ z的含义”是不确定的。