初始化命名空间中的const对象

时间:2013-02-17 01:32:43

标签: c++ namespaces const static-initialization destruction

我在命名空间中初始化一些const对象时遇到了问题。我有一个如下命名空间:

namespace myNamespace{
    const std::string HI = "Hi";
    const std::string BYE = "Bye";

    inline std::vector<std::string> createHiAndByeVector(){
        std::vector<std::string> temp;
        temp.push_back(HI);
        temp.push_back(BYE);
        return temp;
    }

    const std::vector<std::string> HI_AND_BYE = createHiAndByeVector();
}

如果我调试初始化,我可以看到HIBYE都被分配了字符串文字。执行继续到initialziae HI_AND_BYE,但是当我们进入createHiAndByeVector()函数时,HIBYE都不再有值。然后我在push_back()方法中得到了分段错误。如果我查看调用堆栈,我会看到以下行:__static_initialization_and_destruction_0()。到底是怎么回事?我的物体在施工后会立即被毁坏吗?

2 个答案:

答案 0 :(得分:1)

我的猜测是这里的问题违反了One Definition Rule(ODR)。这里的猜测是这个代码实际上是在一个标题中,这也是你将函数声明为内联的原因。

现在,此代码以多个翻译单元(.cpp文件),TU1和TU2编译。这导致两组常量和内联函数。现在,当链接时,常量彼此独立存在,因为它们具有内部链接(命名空间级别的const导致这种情况)。但是,该函数没有内部链接,而是指示链接器通过inline丢弃除一个实例之外的所有实例。现在,剩下的一个用于初始化TU1和TU2中的向量,但它使用其中一个的常量字符串。根据初始化的时间(未定义),它可以工作与否。这基本上是Deamonpog上面提到的初始化顺序惨败。

回到ODR,问题是内联函数被编译两次但它们不相同,因为它们隐式引用不同的字符串常量。如果在标头中有匿名名称空间,则会出现类似问题。顺便说一句:除此之外,这个问题与名称空间无关!有两种方法可以解决这个问题:

  1. 使init函数也是静态的。这将所有这些常数和函数与其他翻译单元中的兄弟分开。
  2. 您只需在标头中声明(extern string const BYE;)常量,并在单独的TU中实现它们(string const BYE = "Bye!";)。这样,您只有一个可以由程序的不同部分共享的实例。

答案 1 :(得分:-1)

我认为这是由于初始化Fiasco。以下链接可以帮助您。问题是全局/静态变量是以随机方式初始化的。没有特定的初始化顺序。所以也许你的HI_AND_BYE在HI或BYE初始化之前被初始化。!!!

Finding C++ static initialization order problems

http://www.parashift.com/c++-faq-lite/static-init-order.html