2

これは問題の可能な解決策として私の頭の中を駆け巡りましたが、これは C++ の何かのかなり明白な技術的違反であるため、失敗する可能性がどのくらいか、別のかなり明白なアプローチがあるかどうかなどを知りたいと思いました。 . これが未定義の動作についての炎上戦争に巻き込まれないことを願っていますが、トピックを考えると、私は少し期待しています.

これは私が書いているコードではありません。私がやろうとしていることを説明しないほど単純化されていないことを願っています。

class Code
{
public:
  bool read(short slot, short& val);
  bool read(short slot, long& val);
  bool read(short slot, double& val);
  // etc
protected:
  unsigned char* m_data;
};
typedef boost::shared_ptr<Code> CodePtr;

class SortedBase
{
protected:
   class Sorter : public std::binary_function<CodePtr,CodePtr,bool>
   {
   protected:
     inline Sorter() {}
     virtual ~Sorter() {}
   public:
     virtual bool operator()(CodePtr left, CodePtr right) PURE;
   };

   inline SortedBase(Sorter* s):m_codeList(s) {}

   typedef std::set<CodePtr,Sorter> TSortedCode;
   TSortedCode m_codeList;
public:
   virtual ~SortedBase() {}
   void fetch(); // populates m_codeList
};

template<class SORT1, class SORT2, class SORT3, class SORT4, class SORT5>
class SortedObject5 : public SortedBase
{
public:
  SortedObject5():SortedBase(m_sorter),m_sorter(this) {}

  something_interesting find(SORT1 val1, SORT2 val2, SORT3 val3, SORT4 val4, SORT5 val5);
protected:
  typedef SortedObject5<SORT1,SORT2,SORT3,SORT4,SORT5> my_class;
  class MySorter : public Sorter
  {
  public:
    MySorter(const my_class& parent):m_parent(parent) {}
    virtual operator()(CodePtr left, CodePtr right);
  protected:
    const my_class& m_parent;
  }

  MySorter m_sorter;
};

ここの意図

テンプレート クラスを作成するときに、テンプレート以外の基本クラスに因数分解されたロジックをできるだけ多く含めると、他のコードが参照できるいくつかの共通クラスを持ち、コードの重複の量を減らすのに役立つことがよくあります。テンプレート パラメータの数が異なる、同じクラスの異なるバージョン。

この場合、CodePtr はコード内の別の場所で生成され (私が書きましたが)、任意の数の任意のデータ型に基づいて要素を検索したいと考えています。最初は std::multimap を検討しましたが、キーは CodePtr のラッパー (または重要なチャンクのコピー) になります。

問題

ステートフル ソーター ファンクター SortedObject5<>::my_sorter を SortedBase::m_codeList のコンストラクターに渡します。ただし、ステートフル ソーターはサブクラスにあるため、STL セットが構築される時点では明らかに構築されません。

いずれかのコンストラクターから m_codeList に挿入または検索を行わない場合、これが問題になるかどうか疑問に思っています。

ステートフル ソーターの免責事項

ステートフルな並べ替えファンクターで使用されるルールは、それが制御する STL コンテナーが空であるか、その後すぐに clear() される間にのみ変更されることを正式に ASSERT() します。

4

1 に答える 1

0

std::set<CodePtr,Sorter>オブジェクトはSorter by 値のインスタンスを格納するため、 Sorter*(ポインターではなく参照であることを意味していましたか?) で構築すると、オブジェクトがスライスされ、基本部分のみが保持されます。

つまり、Sorterコピー コンストラクターが実行され、初期化されていないオブジェクトのコピーが作成されます。未定義の動作が発生します。

それは、のインスタンスを作成することさえできるSorterPURE仮定しています.

@Angewのコメントは良いアプローチを示唆しています。メンバーイディオムのベースを使用するとm_sorter、問題の一部であるオブジェクトが最初に初期化されるようになります。ただし、それはスライスの問題には役立ちません。それを解決するには、ソーターの周りにラッパーが必要です。

typedef std::function<bool(const CodePtr&,const CodePtr&)> SorterFunc;
typedef std::set<CodePtr, SorterFunc> TSortedCode;

そして、ラッパーを set コンストラクターに渡します。

inline SortedBase(SorterFunc s) : m_codeList(s) {}

派生型からを構築するstd::functionと、スライスされません。ただし、コピーされますが、参照ラッパーを使用してそれを防ぐことができます。

  SortedObject5() : BaseFrommember(this), SortedBase(SorterFunc(std::ref(m_sorter))) { }

base-from-member イディオムを使用して基本クラスに格納されているため、 Wherem_sorterは既に初期化されています。BaseFromMember

これ:

  1. m_sorter 最初のものを作成するので、初期化されていないオブジェクトで何もしません
  2. オブジェクトへの参照渡しSorterFunc
  3. そのコピーをSorterFunc(まだ への参照を保持しているm_sorter) を比較関数として使用します。std::set

base-from-member イディオムを使用したくない場合でも、元のコードの未定義の動作を回避するのは簡単です。set(初期化されていないオブジェクトを渡す代わりに) デフォルトで構築し、新しい値を割り当てます。あなたはそれを移入し始めます:

SortedObject5() : m_sorter(this)
{
  this->m_codeList = TSortedCode(SorterFunc(boost::ref(m_sorter)));
}

新しい基本クラス、追加のテンプレート、未定義の動作はありません。

完全な作業コードは次のとおりです。

class SortedBase
{
protected:
   class Sorter : public std::binary_function<CodePtr,CodePtr,bool>
   {
   protected:
     Sorter() {}
     virtual ~Sorter() {}
   public:
     virtual bool operator()(const CodePtr& left, const CodePtr& right) = 0;
   };

   typedef boost::function<bool(const CodePtr&, const CodePtr&)> SorterFunc;

   typedef std::set<CodePtr,SorterFunc> TSortedCode;

   TSortedCode m_codeList;

public:
   virtual ~SortedBase() {}
   void fetch(); // populates m_codeList
};

template<class SORT1, class SORT2, class SORT3, class SORT4, class SORT5>
class SortedObject5 : public SortedBase
{
public:
  SortedObject5() : m_sorter(*this)
  {
    this->m_codeList = TSortedCode(SorterFunc(boost::ref(m_sorter)));
  }

protected:
  typedef SortedObject5<SORT1,SORT2,SORT3,SORT4,SORT5> my_class;

  class MySorter : public Sorter
  {
  public:
    MySorter(const my_class& parent):m_parent(parent) {}
    virtual bool operator()(const CodePtr& left, const CodePtr& right);
  protected:
    const my_class& m_parent;
  };

  MySorter m_sorter;
};
于 2013-05-17T19:07:01.730 に答える