【问题标题】:C++ global variable in namespace [duplicate]命名空间中的C ++全局变量[重复]
【发布时间】:2016-04-14 11:18:32
【问题描述】:

我已经看到了很多关于这个的问题,但没有一个包含关于如何为这个特定用例编译代码的解释。我运行以下命令:g++ main.cpp c.cpp testobj.cpp -o main,但运行它会给我一个Segmentation fault (core dumped)。当我在main.cppmain 方法中有打印语句并删除所有TestObj 代码时,它确实有效。

这是分配C::test 常量的正确方法吗?

ma​​in.cpp:

#include "c.h"
#include "testobj.h"

TestObj testobj;

int main() {
    return 0;
}

c.h:

#ifndef CONSTANTS
#define CONSTANTS

#include <string>

namespace C {
    extern std::string test;
}
#endif

c.cpp:

#include "c.h"

namespace C {
    std::string test = "test";
}

testobj.h:

#ifndef TESTOBJ
#define TESTOBJ

class TestObj {
public:
    TestObj();
};

#endif

testobj.cpp:

#include "testobj.h"
#include <iostream>
#include "c.h"

TestObj::TestObj() {
    std::cout << C::test << std::endl;
}

【问题讨论】:

    标签: c++ namespaces


    【解决方案1】:

    这是由全局静态变量的初始化顺序引起的。它是未定义的,称为static initialization order fiasco。当TestObj::TestObj( 使用C::test - 它还没有被构造。

    常见的解决方法是将全局静态变量移动到函数局部静态变量中,即:

    const std::string getTestString() {
        static std::string test = "test";
        return test;
    }
    

    现在,当您调用getTestString() 时,测试变量将被构造,并且将只执行一次。此外,由于函数中静态变量的 C++11 初始化保证是线程安全的。

    【讨论】:

    • 另外,在静态变量的构造函数中使用std::cout是不安全的,因为std::cout本身就是静态变量,我们也依赖它的初始化。
    • @IgorSemenov 我没想到,因为 C++11 看起来已经修复了 - stackoverflow.com/questions/8784892/…
    【解决方案2】:

    虽然单个translation unit 中的全局变量的初始化顺序已明确定义,但翻译单元之间的顺序不是

    因此,如果main.cpp 源文件中的testobj 对象在C::test 对象之前初始化,那么您确实会有奇怪的行为。

    如果你有多个翻译单元,每个翻译单元都有全局变量,那么你不能依赖它们之间的初始化顺序。

    【讨论】:

    • 我保存将TestObj testobj 的声明更改为TestObj *testobj 并将初始化移动到main() 方法,通过执行*testobj = TestObj()?
    • @martijnn2008 是的,如果您考虑使用安全的指针。 :) main 函数将始终在所有全局变量初始化后调用。
    猜你喜欢
    • 2012-03-13
    • 1970-01-01
    • 2011-03-25
    • 2017-07-24
    • 1970-01-01
    • 2011-08-31
    • 2017-01-04
    • 1970-01-01
    • 2015-04-22
    相关资源
    最近更新 更多