Правильная инициализация статического массива объектов без фиаско порядка инициализации с использованием ссылок на объекты

Я пытаюсь реализовать облегченную карту, просто используя массив элементов, членами которых являются ключ и значение. Содержимое карты известно во время компиляции, поэтому я думаю об использовании массива фиксированного размера следующим образом:

#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), но не смог найти ни одного, связанного с использованием массивов.

  • Могу ли я столкнуться с фиаско порядка инициализации?
  • Если нет, что мешает этому случиться здесь?
  • Имеет ли значение, что я использую массив? Как бы это выглядело, если бы я попытался инициализировать простую переменную, используя const Item anotherItem = ITEM1; например?

0

Решение

Ты используешь ItemMapUser::map в коде, который можно вызвать из
конструктор статического объекта? Нет проблем
инициализация ссылок с неструктурированными объектами, но
будет, если вы используете их до того, как объект будет построен.

Re ваши вопросы:

  1. Нет, если вы на самом деле не используете объекты ссылки
    обозначить в конструкторе статический объект.

  2. В основном, тот факт, что это ссылки, и вы можете
    безопасно инициализировать референ с неструктурированным объектом.
    (Существуют определенные ограничения при наследовании,
    но они не кажутся здесь уместными.)

  3. Это не имеет ничего общего с тем, инициализируете ли вы
    объект или массив. Если вы инициализируете объект
    (член массива или нет), а не ссылка, и вызов
    конструктор копирования, копируемый объект лучше
    построен. Что вы можете гарантировать, только если это определено в
    тот же переводчик.

0

Другие решения

Я бы сказал, что да, вы можете столкнуться с фиаско статического порядка инициализации.

Причина, по которой вы еще не сталкивались с этим, заключается в том, что приложение еще не стало достаточно сложным для создания циклической статической инициализации.

Я не думаю, что использование массива имеет какое-либо значение.

Во всяком случае, это не стоит рисковать. Я бы начал со следующего паттерна и развивал его по мере необходимости, то есть создавая статический класс или любой другой, который лучше всего соответствует вашим целям.

#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!";
}
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);
0
По вопросам рекламы [email protected]