7

このおもちゃのコードのような、テンプレート化されたコンテナー クラスがあります。

template <class ItemType> class MyVector
{
public:
   MyVector() : _numItems(0), _items(NULL) {/* empty */}

   /** Returns a reference to the first item in our array,
     * or a default-constructed item if the array is empty.
     */
   const ItemType & GetFirstItemWithDefault() const
   {
      return (_numItems > 0) ? _items[0] : _defaultItem;
   }

   [other methods omitted because they aren't relevant]

private:
   int _numItems;       // how many valid items (_items) points to
   ItemType * _items;   // demand-allocated
   const ItemType _defaultItem;
};

このクラスは非常に便利に使用できます。どのコードでも "MyVector.h" を #include するだけで、MyVector や MyVector などのオブジェクトの宣言を開始できます。

ただし、気になる点の 1 つは、_defaultItem メンバー変数の存在です。これは、コンテナーが空のときに GetFirstItemWithDefault() に有効な参照を返す機能を与えるためだけに存在します。反対意見は、N 個の MyVector オブジェクトを宣言すると、RAM にも _defaultItem の N 個のコピーが存在することを意味するということです。ただし、それらはすべて同一で読み取り専用であるため、実際には 1 つにつき 1 つだけ存在する必要があります。 MyVector ごとに 1 つではありません。

したがって、明らかな解決策は _defaultItem を static にすることです....しかし、AFAICT にはコストが伴います。これを行うと、古いコードを単純に #include "MyVector.h" して実行することはできなくなります。 .. ユーザーは、自分の .cpp ファイルの 1 つで、その静的変数のストレージを確実に宣言する必要があります。これは、(a) お尻の痛みであり、(b) コードのユーザーが認識しなければならないことを意味します。クラスの内部実装の詳細。_defaultItem はプライベート メンバー変数であるため、クラスのユーザーはそれについて考える必要はなく、その存在に気付く必要さえありません。ましてや、そのためのストレージを宣言する必要があることを知る必要はありません。(そして、2 つの別々のコードが両方ともそのストレージを宣言し、お互いが同じことをしたことを認識していない場合はどうなるでしょうか? 重複シンボル リンカー エラーが発生するのではないでしょうか?)

したがって、私の質問は次のとおりです。MyVector のユーザーがそれについて知る必要がないように、この静的メンバー変数に (インスタンス化された MyVector の型ごとに) 1 つの一意のストレージを自動的に提供するように C++ に指示する方法はありますか? (いくつかの一般的なケースだけでなく、 MyVector<...> のすべての可能なインスタンス化に対して自動である必要があることに注意してください)

4

3 に答える 3

8

そのデフォルト項目を関数に対して static ローカルにしないのはなぜですか?

const ItemType & GetFirstItemWithDefault() const
{
    static const ItemType _default;
    return (_numItems > 0) ? _items[0] : _default;
}

これは、他の関数のデフォルト項目に対して再度チェックしたい場合に必要なものではないかもしれませんが、そのためには別の関数に入れることもできます (それ自体が静的である可能性があります):

static const ItemType& GetDefault() const
{
  static const ItemType _default;
  return _default;
}

デフォルト項目にアクセスする必要がある場合は、その関数を呼び出します。


そうは言っても、デフォルトのアイテムを持つことはあまり良くないと思います。std::vectorまた、それを持っておらず、必要もありません。ベクトルが実行されているかどうかを確認するようにユーザーに指示するだけemptyです。非表示の統計に関する 1 つの問題は、あなたが知らないということですItemType。大量のリソースを消費するクラスである可能性があり、その別のインスタンスを作成しただけです! おそらくそのクラスの設計を再考し、その後に切り替えstd::vectorます。:)

于 2011-06-17T05:57:11.077 に答える
3

したがって、明らかな解決策は _defaultItem を静的にすることです....しかし、コストがかかるAFAICT:そうすると、古いコードを単純に #include "MyArray.h" して移動することはできなくなります。 .. これで、ユーザーは .cpp ファイルの 1 つでその静的変数のストレージを宣言する必要があります。これは (a) 面倒です

いいえ。この恐怖は心配ではありません。sでは、同じファイルで変数をtemplate宣言できます (宣言する必要があります) 。static

template <class ItemType> class MyVector
{
  const ItemType _defaultItem;
};
template <class ItemType>
const ItemType MyVector<ItemType>::_defaultItem; // ok (no multiple symbols)

また、このstaticメンバーはGetFirstItemWithDefault()が呼び出された場合にのみインスタンス化されることに注意してください。したがって、冗長な割り当てについても心配する必要はありません。

唯一の懸念は、オブジェクトが一般的にデフォルトのコンストラクターに依存するため、デフォルトのコンストラクターをすべてに提供することです(これについては、すでに気にかけている必要があります)。それでおしまい。ItemTypestatic

于 2011-06-17T06:51:53.990 に答える
3

テンプレートの場合は、コンパイラが魔法のように処理します。静的メンバーをヘッダーに入れるだけで、コンパイラーはそれが一度だけインスタンス化されることを確認します。

template <class ItemType> 
class MyVector
{
public:
    //...
private:
    static const ItemType _defaultItem;
}; 


template <class ItemType> 
const ItemType MyVector<ItemType>::_defaultItem;
于 2011-06-17T06:38:11.053 に答える