正确初始化静态对象数组而不会遇到使用对象引用的初始化顺序失败

时间:2013-09-02 14:56:04

标签: c++ arrays reference static-order-fiasco

我正在尝试通过简单地使用其成员是键和值的元素数组来实现轻量级映射。地图内容在编译时是已知的,所以我想如下使用固定大小的数组:

#include "stdafx.h"
#include <string>

// class Item is declared in file1.h. Definition could be in file1.cpp.
class Item
{
public:
    Item(const std::string name) : m_name(name) {}
    const std::string GetName() const { return m_name; }

private:
    const std::string m_name;
};

// The static consts are declared in file2.h which includes file1.h.
static const Item ITEM1 = std::string("Item1");
static const Item ITEM2 = std::string("Item2");
static const Item ITEM3 = std::string("Item3");
static const Item ITEM4 = std::string("Item4");

// ItemMapEntry and ItemMapUser is defined in file3.h...
struct ItemMapEntry
{
    const Item& key;
    const Item& value;
};

class ItemMapUser
{
public:
    void Run();

private:
    static const ItemMapEntry map[];
};

// and declared in file3.cpp which includes file2.h.
const ItemMapEntry ItemMapUser::map[] =
{
    { ITEM1, ITEM2 },
    { ITEM3, ITEM4 }
};

void ItemMapUser::Run()
{
    for (int i = 0; i < (sizeof(map) / sizeof(map[0])); i++)
    {
        printf("%s        %s\n", map[i].key.GetName().c_str(), map[i].value.GetName().c_str());
    }
}

// main.cpp includes file3.h.
int main()
{
    ItemMapUser itemMapUser;
    itemMapUser.Run();
}

现在我的问题:代码片段按预期工作但我不知何故感觉我依赖于初始化顺序让ITEM1到ITEM4的内容初始化,然后再在ItemMapUser :: map中使用它们。我搜索了很多关于这个主题的问题(尤其是那些带有static-order-fiasco标签的问题)但找不到任何与数组使用相关的问题。

  • 我可能会遇到初始化命令fiasco吗?
  • 如果不是,是什么阻止它在这里发生?
  • 我使用的是数组吗?如果我尝试使用const Item anotherItem = ITEM1;初始化一个简单的变量,那会是什么样子?

3 个答案:

答案 0 :(得分:0)

您是否可以在可以调用的代码中使用ItemMapUser::map 静态对象的构造函数?这里没有问题 用未构造的对象初始化引用,但是 如果你在构造对象之前使用它们就会有。

回答你的问题:

  1. 除非您实际使用引用的对象 在静态对象的构造函数中指定。

  2. 基本上,这些都是参考,你可以 使用未构造的对象安全地初始化referene。 (涉及继承时存在某些限制, 但它们似乎与此无关。)

  3. 它与您是否正在初始化无关 对象或数组。如果您正在初始化对象 (数组的成员与否)而不是引用,并调用 复制构造函数,被复制的对象最好是 建造。只有在中定义时才能保证 同一个翻译单位。

答案 1 :(得分:0)

我会说是的,你可能会遇到静态初始化命令fiasco。

你还没有遇到它的原因是应用程序还不够复杂,无法创建循环静态初始化。

我认为使用数组没有任何区别。

无论如何,这不是值得冒的风险。我将从以下模式开始,并根据需要进行演变,即创建一个静态类或最适合您的目的。

#include <iostream>
#include <string>
#include <map>
using namespace std;


// Define safely in any module and use safely from any module.
// With C++11 use of an initializer list could eliminate the init statement.
// If you want to define the constants separately from the map use of constexpr
// should preclude any initialization order issues.
static const map<string, string>& Map()
{
   static map<string, string> map;
   static bool init = false;

   if(!init)
   {
      map["Item1"] = "Item2";
      map["Item3"] = "Item4";
      init = true;
   }

   return map;
}


int main()
{
   cout << "Hello world!";
}

答案 2 :(得分:0)

也许这个问题在提问过程中被简化了,但是在这里发生了大量的颠簸,其中基本上要简单得多。

struct entry {
    const char *key;
    const char *value;
};

entry data_map[] = {
    "Item1", "Item2",
    "Item3", "Item4",
    0,       0
};

for (entry *current = data_map; current->key != 0; ++current)
    printf("%s %s\n", current->key, current->value);