未初始化变量与类型安全性之间的联系

时间:2018-06-23 14:16:50

标签: c++ double undefined

我想问为什么使用未初始化的变量被认为是非类型安全的?

我正在从该站点上的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定义了+?

3 个答案:

答案 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的含义”是不确定的。