【问题标题】:Global const initializing and difference between constructor in .h or .cpp file.h 或 .cpp 文件中的全局常量初始化和构造函数之间的区别
【发布时间】:2010-12-09 10:25:41
【问题描述】:

我想知道为什么有时我在单独的 .h 文件中定义的全局常量在我需要时没有正确初始化。一些测试导致我遇到我无法理解的情况。不知道怎么解释,代码如下:

main.cpp

#include <iostream>
#include "class.h"
using namespace std;

A a;
B b;

int main(int argc, char* argv[]){
A aa;
B bb;
cout<<a.a<<" "<<aa.a<<endl;
cout<<b.b<<" "<<bb.b<<endl;
return 0;
}

class.h

#ifndef CLASS_H
#define CLASS_H
#include "const.h"

class A {
public:
A();
float a;
};

class B {
public:
B():b(CONST){}
float b;
};
#endif

class.cpp

#include "class.h"
A::A()
: a(CONST){}

const.h

#ifndef CONST_H
#define CONST_H
#include <limits>
using namespace std;

const float CONST = numeric_limits<float>::has_infinity ? 
        -numeric_limits<float>::infinity() : 
        -numeric_limits<float>::max();
#endif

运行上面的代码后,我得到:

0 -1.#INF
-1.#INF -1.#INF

实际上我想获得 4 次“-1.#INF”。 为什么会这样?如果 CONST 将是 '1' 而不是上面的公式,它将完美地工作。

我可以通过制作静态 getConst() 方法来“修复”它:

static float getConst(){
static const float CONST = numeric_limits<float>::has_infinity ? 
        -numeric_limits<float>::infinity() : 
        -numeric_limits<float>::max();
return CONST;}

但它只是不“感觉”正确。另一方面,我只需要上面的两个......但也许还有其他方法?

而且,最重要的是,为什么 B 类得到“正确”的 CONST 而 A 类却没有?

【问题讨论】:

    标签: c++ constructor constants


    【解决方案1】:

    不保证全局对象在不同翻译单元中的初始化顺序。

    请看一下这个 stackoverflow 问题:Static variables initialisation order

    【讨论】:

    • 谢谢,这解释了很多。有趣的是,我相信它现在应该一直以相同的方式运行,因为我使用的是相同的编译器等,但是当我在几秒钟前打开并重新编译这个项目时,它很快就会为 A::a 初始化 CONST正确初始化
    【解决方案2】:

    常量对象具有内部链接,因此您会在每个包含const.h 的编译单元中获得CONST 的单独副本。在这种情况下,您将在main.cpp 中获得一个,在class.cpp 中获得一个。 main.cpp 中还有两个全局对象。

    C++ 没有定义不同编译单元中全局对象的初始化顺序。 As 的构造函数是从 main.cpp 调用的,并且需要来自 class.cpp 的全局常量,它可能尚未初始化。在您的特定情况下,它还没有,因此您得到的值不正确。 Bs 构造函数是内联的,因此它使用来自 main.cpp 的全局常量,该常量已被初始化,因为它之前在同一编译单元中定义。

    通过使常量成为函数静态对象,现在可以保证在第一次调用该函数时对其进行初始化。

    【讨论】:

    • 哇,感谢您的全面回答。我希望 B 已正确初始化而 A 未正确初始化的事实是由 B 的内联构造函数引起的,但这只是因为 main.cpp “走运”,而 class.cpp 没有。但是,据我了解,在 main 函数开始运行之前,这个 const 不可能不被初始化?
    • @Koger:B 的正确行为实际上是有保证的;在单个编译单元中,全局对象按照定义的顺序进行初始化,CONSTB 之前定义(在头文件中)。是的,它们都将在main 开始之前被初始化。
    • class.cpp 不也是单一编译单元吗?并且它理论上包含 class.h 和 const.h 和 main.cpp 一样,所以 CONST 在 A 之前定义。
    【解决方案3】:

    我在任何地方都看不到const.h 的内容,所以我只能猜测CONST 是什么(宏?)。

    除此之外,在您的代码示例中,成员变量 A::a 未初始化。因此,它可以有任何值——它是未初始化的。

    【讨论】:

    • 看起来有人编辑了我的问题,让它看起来更整洁。现在 const.h 更加明显。并且 A::a 在 class.cpp 文件中初始化
    【解决方案4】:

    如果我正确理解了您的问题,那么我认为问题在于未定义任何全局对象的初始化顺序。

    【讨论】:

      猜你喜欢
      • 2017-02-07
      • 2013-02-10
      • 2019-11-12
      • 1970-01-01
      • 2010-12-21
      • 1970-01-01
      • 1970-01-01
      • 2014-09-17
      相关资源
      最近更新 更多