2013-09-02 3 views
0

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

#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, и их содержимое было инициализировано, прежде чем использовать их в Map ItemMapUser ::. Я просмотрел многие вопросы, относящиеся к этой теме (особенно те, у которых был тег static-order-fiasco), но не смог найти ни одного, связанного с использованием массивов.

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

Также см [AddressSanitizerInitializationOrderFiasco] (https://github.com/google/sanitizers/wiki/AddressSanitizerInitializationOrderFiasco). – jww

ответ

0

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

Re вопросы:

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

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

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

+0

Спасибо за ответ. У меня есть привычка использовать ссылки везде, где мне не нужно что-то другое, и это, очевидно, хорошая привычка в этом случае (и во многих других ...). Не могли бы вы дать дополнительное объяснение ограничениям при наследовании? –

+0

@RolandSarrazin Если фактические объекты «Derived», а ссылка относится к «базе», то преобразование 'Derived &' to 'Base &' является неопределенным поведением до тех пор, пока объект, на который делается ссылка, не построил ; см. §3.8/5. (На практике он будет работать до тех пор, пока не будет задействовано наследование наследование , и в зависимости от компилятора он может работать с виртуальным наследованием, но это не обязательно, и Я был поражен этим.) –

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

I не намереваются использовать карты как 1) количество записей, безусловно, не станет огромным, и 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); 
+0

Благодарим вас за предложение по оптимизации, но моя цель состояла в том, чтобы написать компиляционный и исполняемый фрагмент из нашей структуры программного обеспечения, которая намного сложнее. Комментарии кодов относительно разных включенных файлов отражают фактическую структуру. –