2

我在初始化命名空间中的一些 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(). 到底是怎么回事?我的对象在构建后会立即被销毁吗?

4

2 回答 2

1

我的猜测是这里的问题违反了单一定义规则(ODR)。这里的猜测是这段代码实际上是在一个头文件中,这也是你将函数声明为内联的原因。

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

回到 ODR,问题在于内联函数被编译了两次,但它们并不相同,因为它们隐式引用了不同的字符串常量。当您在标头中有匿名名称空间时,也会出现类似的问题。BTW:除此之外,这个问题与命名空间无关!有两种方法可以解决这个问题:

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

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

查找 C++ 静态初始化顺序问题

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

于 2013-02-17T02:07:37.420 回答