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();
}

私の質問に: コード スニペットは意図したとおりに動作しますが、ItemMapUser::map で使用する前に ITEM1 から ITEM4 のコンテンツを初期化する初期化順序に依存しているように感じます。このトピックに関する多くの質問 (特に static-order-fiasco タグが付いているもの) を検索しましたが、配列の使用に関連するものは見つかりませんでした。

  • 初期化命令の失敗に遭遇する可能性はありますか?
  • いいえの場合、ここでの発生を妨げているのは何ですか?
  • 配列を使用していることは重要ですか? const Item anotherItem = ITEM1;たとえば、単純な変数を初期化しようとすると、どのようになりますか?
4

3 に答える 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!";
}
于 2013-09-02T15:30:34.413 に答える
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);
于 2013-09-02T15:33:47.250 に答える
0

ItemMapUser::map静的オブジェクトのコンストラクターから呼び出すことができるコードで使用しますか? 構築されていないオブジェクトで参照を初期化しても問題はありませんが、オブジェクトが構築される前にそれらを使用すると問題が発生します。

あなたの質問について:

  1. 静的オブジェクトのコンストラクターで参照が指定するオブジェクトを実際に使用しない限り、そうではありません。

  2. 基本的に、これらは参照であり、構築されていないオブジェクトでレフェレンを安全に初期化できるという事実。(継承が関係する場合には一定の制限がありますが、ここでは関係ないようです。)

  3. オブジェクトを初期化するか配列を初期化するかは関係ありません。参照ではなくオブジェクト (配列のメンバーであるかどうかに関係なく) を初期化し、コピー コンストラクターを呼び出す場合は、コピーされるオブジェクトを構築する必要があります。同じ翻訳単位で定義されている場合にのみ保証できます。

于 2013-09-02T15:10:23.537 に答える