初始化变量有多重要?
适当的初始化是否可以避免内存泄漏或具有性能优势?
null
由通用编译器初始化为0(或),但在进行发行时则为随机垃圾。(尽管我的C ++知识来自大约10年前,但情况可能已经发生了变化)
初始化变量有多重要?
适当的初始化是否可以避免内存泄漏或具有性能优势?
null
由通用编译器初始化为0(或),但在进行发行时则为随机垃圾。(尽管我的C ++知识来自大约10年前,但情况可能已经发生了变化)
Answers:
未初始化的变量使程序不确定。每次程序运行时,它的行为都可能不同。操作环境,一天中的时间,月相以及它们的排列等无关的更改会影响这些守护程序的显示方式和时间。该程序可能在缺陷出现之前运行一百万次,他们可能每次都运行一次,或者运行另一百万次。许多问题归结为“故障”而被忽略,或者来自客户的缺陷报告被关闭为“不可重现”。您多久重启一次计算机以“解决”问题?您多久对客户说一次“从未见过这种情况,请告诉我您是否再见到它”-希望他们(他们)完全知道他们不会!
由于缺陷的重现在测试环境中几乎是不可能的,因此几乎不可能找到并修复。
错误可能要花费数年才能浮出水面,通常在代码中被认为是可靠和稳定的。缺陷被认为是在最近的代码中-追踪到它可能花费更长的时间。更改编译器,更改编译器,甚至添加一行代码也可以更改行为。
初始化变量具有巨大的性能优势,不仅因为正确运行的程序要比不正常运行的程序快得多,而且开发人员花费更少的时间查找和修复不应存在的缺陷,而将更多的时间用于“实际”工作。
初始化变量的另一个重要优点是代码的原始作者必须决定将变量初始化为什么。这并不总是琐碎的练习,当不是琐碎的练习时,可能表明设计不佳。
内存泄漏是一个不同的问题,但是正确的初始化不仅可以帮助防止它们,还可以帮助检测它们并找到源-高度依赖于语言,这确实是一个单独的问题,值得我进一步探讨。在这个答案。
编辑:在某些语言(例如C#)中,无法使用未初始化的变量,因为程序将无法编译,或者在执行时报告错误(如果完成)。但是,许多具有这些特征的语言都具有与潜在不安全代码的接口,因此在使用此类接口时不要引入未初始化的变量,请务必小心。
尝试使用未初始化的变量始终是一个错误,因此将该错误发生的可能性降到最低是有意义的。
编程语言缓解该问题的最常用方法可能是自动初始化为默认值,因此至少如果您忘记初始化变量,它将类似于0
而不是0x16615c4b
。
如果您碰巧需要将变量初始化为零,则可以解决大部分错误。但是,使用一个初始化为错误值的变量与使用一个根本没有初始化的变量一样糟糕。实际上,有时甚至更糟,因为错误可能更微妙且难以检测。
函数式编程语言不仅通过禁止未初始化的值,而且通过完全禁止重新分配来解决此问题。这就消除了问题,并没有像您想象的那样严格。即使在非功能性语言中,如果您等待声明一个变量,直到拥有一个正确的值来对其进行初始化,那么您的代码往往会更健壮。
就性能而言,它可以忽略不计。最糟糕的情况是,对于未初始化的变量,您会额外分配一个空间,并且占用一些内存的时间超过了必要。好的编译器可以在很多情况下优化差异。
内存泄漏是完全不相关的,尽管正确初始化的变量往往会在较短的时间内出现在范围内,因此程序员意外泄漏的可能性可能较小。
初始化,意味着初始值很重要。如果初始值很重要,那么可以,显然,您必须确保已将其初始化。如果没关系,则意味着它将在以后初始化。
不必要的初始化会浪费CPU周期。尽管这些浪费的周期在某些程序中可能无关紧要,但在其他程序中,每个周期都很重要,因为速度是最主要的问题。因此,了解一个人的性能目标以及是否需要初始化变量非常重要。
内存泄漏是一个完全不同的问题,通常涉及一个内存分配器函数来发布并稍后回收内存块。想想一个邮局。你去找一个邮箱。他们给你一个。您要求另一个。他们给你另一个。规则是,使用完邮箱后,您需要将其退还。如果您忘了把它还给他们,他们仍然会认为您拥有它,并且该盒子不能被其他任何人重复使用。因此,有一大堆内存被占用并且未被使用,这就是所谓的内存泄漏。如果您在某个时候一直要求输入框,则将耗尽内存。我已经简化了这一点,但这是基本思想。
正如其他人所说,这取决于语言。但是,我将演示有关初始化变量的Java(和有效Java)想法。这些应该可用于许多其他高级语言。
用static
Java 标记的类变量就像常量。这些变量通常应为最终变量,并在定义后使用=
类初始化程序块或在其内部直接进行初始化static { // initialize here }
。
与许多高级语言和脚本语言一样,将自动为字段分配默认值。对于数字,char
这将是零值。对于Strings和其他对象,它将为null
。现在null
很危险,应谨慎使用。因此,应尽快将这些字段设置为有效值。构造函数通常是一个理想的选择。为了确保在构造函数中设置变量,并且以后不更改变量,可以用final
关键字标记它们。
尝试抵制null
用作某种标志或特殊值的冲动。最好包括一个特定的字段来保持状态。一个名称state
使用State
枚举值的字段将是一个不错的选择。
因为调用者将看不到参数值的更改(它是引用对象还是诸如整数等基本类型的引用),所以应将参数标记为final
。这意味着变量本身的值不能更改。请注意,可变对象实例的值可以更改,但是引用不能更改以指向其他对象null
。
局部变量不会自动初始化;必须先初始化它们,然后才能使用它们的值。确保变量已初始化的一种方法是直接将它们初始化为某种默认值。然而,这是你应该不会做。大多数情况下,默认值不是您期望的值。
最好仅在需要该变量的位置精确地定义该变量。如果变量仅取一个值(对于良好代码中的大多数变量而言都是正确的),则可以标记该变量final
。这样可以确保为局部变量分配的恰好是一次,而不是零次或两次。一个例子:
public static doMethod(final int x) {
final int y; // no assignment yet, it's final so it *must* be assigned
if (x < 0) {
y = 0;
} else if (x > 0) {
y = x;
} else {
// do nothing <- error, y not assigned if x = 0
// throwing an exception here is acceptable though
}
}
请注意,如果变量在使用前仍未初始化,许多语言都会警告您。查看语言规范和论坛,看看是否不必担心。
初始化变量(隐式或显式)至关重要。不初始化变量总是一个错误(但是,它们可能会隐式初始化。请参见下文)。像C#编译器这样的现代编译器(例如)将其视为错误,并且不允许您执行代码。未初始化的变量就是毫无用处且有害的。除非要创建一个随机数生成器,否则您期望通过一段代码来产生确定性和可复制的结果。这只有在开始使用初始化变量时才能实现。
真正有趣的问题是变量是自动初始化还是您必须手动进行初始化。这取决于所使用的语言。例如,在C#中,字段(即类级别的“变量”)始终会自动初始化为该变量类型的默认值default(T)
。该值对应于由全零组成的位模式。这是语言规范的一部分,而不仅仅是语言实现的技术细节。因此,您可以放心地依靠它。如果(且仅)在语言规范中指出隐式初始化变量,则不要显式初始化变量是安全的。如果需要另一个值,则必须显式初始化变量。然而; 在C#中,局部变量(即在方法中声明的变量)不会自动初始化,因此您必须始终显式初始化变量。