0

C++ でジェネリック ストレージ クラスを作成しようとしています。次のコードを見ると、string/のマップを保存AnyTypeしてアクセスしたいと考えています。

  class StoresTestC
  {
  public:
    template < class SettingsType >
    std::map< std::string, SettingsType >* getStore(std::string const&);
  private:
    std::map< std::string, void* > stores_;
  };

  template < class SettingsType >
  std::map< std::string, SettingsType >* StoresTestC::getStore(std::string const& name)
  {
    if (stores_.count(name) > 0)
    {
      void* temp = this->stores_[name];
      return (std::map< std::string, SettingsType >*)(temp);
    }
    else
    {
      std::map< std::string, SettingsType > * result = new std::map< std::string, SettingsType > ();
      this->stores_[name] = result;
      return result;
    }
  }

そうすることには2つの明らかな危険があると思います。

  1. 間違って呼び出すとSettingsType/name間違ったキャストを呼び出すと、私の知る限り(間違っている可能性があります)、未定義の動作につながります。

  2. メモリ リークが発生しますが、その解決策があります (ここで公開するのは 2 時間もかかりました)。

他に問題が発生する可能性があり、予測できることはありますか?

4

3 に答える 3

2

まず一歩下がって、本当にやりたいことを確認してください。次に、もう一度デザインを見てください。

OK、まだこの機能が必要ですか?

が常に型std::map<std::string, boost::any>である場合に使用します。次に、アイテムを元に戻すためにまたは何らかのメカニズムを使用すると、それが正しいタイプであるか、スローされることが保証されるため、未定義の動作のリスクはありません。さらに、値によるものであるため、メモリリークの可能性もありません。boost::anymapany_castany

shared_ptr<void*>また、元のソリューションで a を使用すると、そこに格納されている元のタイプを削除する方法を覚えているshared_ptrので、言及したメモリリークを取り除くことにも注意してください。

編集:このようなものに関して、他に明らかな技術的問題は見られません。ただし、このようなマップを使用すると、将来の保守担当者に認知(「グロッキング」) 問題が発生する可能性があり、コードの複雑さが多少増加することに注意してください。

于 2012-12-20T17:47:16.987 に答える
1

はい、ポイント1についての疑問は正しいです(ポイント2はあなたが言及したように解決できるはずですが、含まれているマップのデストラクタを正しく呼び出す必要があると考えてください)。

SettingsTypeクライアントが維持し、std::string「typename」表現を同期させる単純なメカニズムを提供せずに、そのようなインターフェースを公開するつもりはありません。単純なタイプミスが全体を台無しにする可能性があります。boost::any値を目的の/期待される結果タイプにキャストしようとするとすぐに、これを例外で表現すると思います。

なぜstd::stringここで代表が必要なのですか?たとえば、RTTI を使用する場合は、使用に使用されるキーを非表示にすることができstores_ますtypeid()

于 2012-12-20T17:56:48.207 に答える
0

とにかくマップを取得するには、型をテンプレート パラメーターとして渡す必要があるため、型ごとに 1 つのマップだけでよいでしょうか?

namespace StoresTest {
  template<typename T>
  struct MapStruct {
    static std::map<std::string, T> the_map;
  };

  template<typename T> std::map<std::string, T> MapStruct<T>::the_map;

  template<typename T>
  inline std::map<std::string, T>& getStore()
  { return MapStruct<T>::the_map; }
}

次に、たとえば、次のようにして値型のマップを取得できFooます

std::map<std::string, Foo>& foo_map = StoresTest::getStore<Foo>();

タイプに名前を付ける必要はなくなりましstringたが、他の理由が必要な場合は追加できます。

于 2012-12-20T17:55:22.827 に答える