【问题标题】:What benefit is there of allowing a variable to be left uninitialized?允许变量未初始化有什么好处?
【发布时间】:2010-08-09 02:00:21
【问题描述】:

在许多语言中,您可以在初始化变量之前声明并使用它。

例如在C++中,可以写一个sn-p如:

int x;
cout << x;

这当然会返回不可预测的(好吧,除非你知道你的程序是如何映射内存的)结果,但我的问题是,为什么编译器允许这种行为?

允许使用未初始化的内存是否有一些应用或效率?

编辑:我突然想到,将初始化留给用户会最大限度地减少对寿命有限(写入周期)的内存介质的写入。只是上述“性能”标题下的一个具体示例。谢谢。

【问题讨论】:

    标签: c++ memory variables mapping initialization


    【解决方案1】:

    我的想法(我以前错了,问问我的妻子吧)是它只是该语言早期版本的遗留物。

    C 的早期版本不允许您在函数中任何您想要的位置声明变量,它们必须位于顶部(或者可能位于块的开头,我很难记住,因为我现在很少这样做了)。

    此外,只有在知道变量应该是什么时,您才会有设置变量的愿望,这是可以理解的。如果您接下来要做的只是覆盖该值(这就是人们从这里获得性能的地方),那么将变量初始化为某个东西是没有意义的。

    这就是为什么有必要允许未初始化的变量,尽管在初始化它们之前你仍然不应该使用它们,而且好的编译器会发出警告让你知道.

    在 C++(以及后来的 C 版本)中,您可以在函数的任何位置创建变量,您确实应该同时创建并初始化它。但这在早期是不可能的。你必须使用类似的东西:

    int fn(void) {
        int x, y;
        /* Do some stuff to set y */
        x = y + 2;
        /* Do some more stuff */
    }
    

    现在,我会选择:

    int fn(void) {
        int y;
        /* Do some stuff to set y */
        int x = y + 2;
        /* Do some more stuff */
    }
    

    【讨论】:

    • +1 多年来我一直是 C/C++,我也同意这一点。也在沿着这条线输入回复,你打败了我:) 用有意义的值初始化一个变量是明智的,它尽可能接近使用它的主代码逻辑 - 距离度量。
    • 现代编译器的 +1 会警告你。只需将警告级别保持在最高级别,然后使所有警告错误,您与强制人们在使用前进行初始化具有相同的效果。仅仅因为人类懒惰并不意味着我们不能用智能编译器来弥补:-) 万岁或编译器霸主。
    • 实际上,我可能会创建一个替代函数,以便我可以编写 int y = alternate() 并且也没有统一化的 y。要是我们能有类似 Python 的声明就好了:if test: y = 3; else: y = 4 可以大大防止未初始化的变量,而不必在任何地方创建单行函数。
    【解决方案2】:

    编程中最古老的借口:它提高了性能!

    编辑:阅读您的 cmets,我同意 - 几年前,性能的重点是 CPU 周期数。我的第一个 C 编译器是传统的 C(ANSI C 之前的那个),它允许编译各种令人讨厌的东西。在这些现代时代,绩效与客户投诉的数量有关。正如我告诉我们招聘的应届毕业生一样——“我不在乎这个项目给出错误答案的速度有多快”。使用现代编译器和开发的所有工具,编写更少的错误,每个人都可以按时回家。

    【讨论】:

    • 不声明它不会进一步提高性能吗?这样,甚至不需要为变量分配内存。任何引用此类代码的性能的人都是完全错误的。
    • 关键字是oldest。 40 年前,当 C 语言被开发时,“浪费”一两条指令来自动初始化一个变量实际上可能很重要。
    • 浪费一条指令可能很有价值,但就性能而言,拥有额外的指令(或两条或三条)会使应用程序的性能降低。
    • C++ 程序不仅仅适用于功能强大的桌面。它们也用于小型微控制器(C 是这样),编写微控制器的人不想放弃额外的指令(不仅仅是时间,而是空间),他们为什么要这样做;他们知道使用未初始化内存的相关问题,所以当他们不需要时,为什么还要支付(初始化)成本。我们是否想对每个人强制执行成本以保护一些没有经验的程序员?我会说它们已经受到保护;现代编译器总是会警告你这个问题。
    • @martin - 我同意。我关于使用现代工具和现代编译器的观点是,它们可以配置为检测潜在问题并发出警告,然后开发人员可以做出决定。
    【解决方案3】:

    某些 API 旨在通过传入的变量返回数据,例如:

    bool ok;
    int x = convert_to_int(some_string, &ok);
    

    它可能会在函数内部设置'ok'的值,所以初始化它是一种浪费。

    (我不提倡这种风格的 API。)

    【讨论】:

    • 对于这个的“真实世界”用法,请参阅 Qt 的 QString 类:doc.qt.nokia.com/4.6/qstring.html#toInt 作为示例。注意 bool* ok。
    • 取决于函数参数是OUT类型还是INOUT类型。
    • 与标准输入流相同:bool ok; std::cin &gt;&gt; ok;
    【解决方案4】:

    简短的回答是,对于更复杂的情况,编译器可能无法确定在初始化之前是否使用了变量。

    例如。

    int x;
    if (external_function() == 2) {
       x = 42;
    } else if (another_function() == 3) {
       x = 49;
    }
    yet_another_function( &x );
    cout << x;   // Is this a use-before-definition?
    

    如果好的编译器能够发现可能的 use-before-initialize 错误,他们会给出警告消息,但对于复杂的情况 - 特别是涉及多个编译单元 - 编译器无法判断。

    至于语言是否应该允许未初始化变量的概念,那是另一回事。 C# 在将每个变量定义为使用默认值初始化时略有不同。大多数语言(C++/C/BCPL/FORTRAN/Assembler/...)让程序员决定初始化是否合适。好的编译器有时可以发现不必要的初始化并消除它们,但这不是给定的。用于更晦涩硬件的编译器往往在优化方面投入的精力较少(这是编译器编写的难点),因此针对此类硬件的语言往往不需要不必要的代码生成。

    【讨论】:

      【解决方案5】:

      也许在某些情况下,在需要它之前不初始化内存会更快(例如,如果您在使用变量之前从函数返回)。无论如何,我通常都会初始化所有内容,我怀疑它会在性能上产生任何真正的不同。我敢肯定,编译器将有自己的方式来优化无用的初始化。

      【讨论】:

        【解决方案6】:

        某些语言对某些变量类型有默认值。话虽如此,我怀疑任何语言都不会显式初始化它们是否会带来性能优势。但是缺点是:

        • 它必须被初始化并且没有完成的可能性有崩溃的风险
        • 意料之外的价值
        • 其他程序员缺乏明确性和目的

        我的建议是始终初始化您的变量,并且一致性会得到回报。

        【讨论】:

          【解决方案7】:

          根据变量的大小,以性能的名义保持未初始化的值可能被视为微优化。加载 double 所需的额外两三个周期会对相对较少的程序(与广泛的软件类型相比)产生负面影响;但是,假设变量非常大,延迟初始化直到非常清楚需要初始化可能是一个好主意。

          【讨论】:

            【解决方案8】:

            for 循环样式

            int i;
            for(i=0;i<something;++i){
                .......
            }
            do something with i
            

            并且您希望 for 循环看起来像 for(init;condition;inc)

            这是绝对必要的

            bool b;
            do{
                ....
                b = g();
                ....
            }while(!b);
            

            具有长嵌套名称的水平屏幕空间

            用于调试可见性的更长寿命范围

            非常偶尔的表现

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2017-12-07
              • 1970-01-01
              • 2013-07-05
              • 2015-09-06
              • 1970-01-01
              • 2017-09-14
              • 1970-01-01
              • 2019-05-25
              相关资源
              最近更新 更多