Est-il possible d'avoir une variable membre statique dans ma classe basée sur un modèle, sans que l'utilisateur de la classe ait à le savoir?

StackOverflow https://stackoverflow.com/questions/6381872

Question

J'ai une classe de conteneur basée sur un modèle, quelque chose comme ce code de jouet:

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

Cette classe est vraiment pratique à utiliser - n'importe quel code peut simplement #inclure "MyVector.h" puis commencer à déclarer des objets de type MyVector et MyVector et ainsi de suite, et tout fonctionne Just (tm) sans avoir besoin de rien .

Une chose qui me dérange un peu, cependant, est la présence de la variable membre _defaultItem, qui est là uniquement pour donner à GetFirstItemWithDefault () la possibilité de renvoyer une référence valide lorsque le conteneur est vide. L'objection est que si je déclare N objets MyVector, cela signifie que N copies de _defaultItem seront également présentes dans la RAM --- même si elles sont toutes identiques et en lecture seule, et donc il ne doit vraiment y en avoir qu'une par processus, pas un par MyVector.

Donc, la solution évidente est de rendre _defaultItem statique ... mais AFAICT qui a un coût: si je fais cela, il n'est plus possible pour aucun ancien morceau de code de simplement #inclure "MyVector.h" et allez ... maintenant l'utilisateur doit être sûr de déclarer le stockage pour cette variable statique dans l'un de ses fichiers .cpp, ce qui est (a) une douleur dans le cul, et (b) signifie que l'utilisateur du code a être au courant des détails de l'implémentation interne de la classe. Puisque _defaultItem est une variable membre privée, l'utilisateur de la classe ne devrait pas avoir à y penser ni même à se rendre compte qu'elle existe, encore moins à savoir qu'il a besoin de déclarer le stockage pour elle. (et que se passe-t-il si deux morceaux de code distincts déclarent tous les deux un stockage, chacun ne sachant pas que l'autre a fait la même chose? Cela ne provoquerait-il pas une erreur de l'éditeur de liens de symboles en double?)

Par conséquent, ma question est la suivante: est-il possible de dire à C ++ de fournir automatiquement un stockage unique (par type instancié de MyVector) pour cette variable membre statique, afin que les utilisateurs de MyVector n'aient pas à le savoir? (Notez que cela devrait être automatique pour toutes les instanciations possibles de MyVector <...>, pas seulement pour quelques cas courants)

Était-ce utile?

La solution

S'il s'agit d'un modèle, le compilateur fera la magie pour vous.Mettez simplement le membre statique dans l'en-tête, et le compilateur veillera à ce qu'il ne soit instancié qu'une seule fois.

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


template <class ItemType> 
const ItemType MyVector<ItemType>::_defaultItem;

Autres conseils

Pourquoi ne pas rendre cet élément par défaut statique local à la fonction?

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

Ce n'est peut-être pas ce que vous voulez si vous voulez vérifier à nouveau l'élément par défaut dans une autre fonction, mais pour cela, vous pouvez simplement le mettre dans une fonction distincte (qui peut être statique en soi):

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

Et appelez cette fonction lorsque vous avez besoin d'accéder à l'élément par défaut.


Cela dit, je pense qu'avoir un élément par défaut n'est pas vraiment sympa.std::vector ne l'a pas non plus et n'en a pas besoin.Dites simplement à l'utilisateur de vérifier si le vecteur est empty et c'est terminé.Un problème avec la statique cachée est que vous ne connaissez pas ItemType.Ce pourrait être une classe qui mange des tonnes de ressources et vous venez d'en faire une autre instance!Peut-être repenser la conception de cette classe et après cela, passer à un std::vector.:)

La solution évidente est donc de faire _defaultItem static .... mais AFAICT qui a un coût: si je fais ça, ce n'est plus possible pour aucun ancien morceau de code pour simplement #inclure "MyArray.h" et c'est parti ... maintenant l'utilisateur a pour être sûr de déclarer le stockage pour cela variable statique dans l'un de ses .cpp fichiers, ce qui est (a) pénible

Non .Cette peur est inquiétante.Dans templates, vous pouvez (devez) déclarer la variable static dans le même fichier.

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

Notez également que ce membre static ne sera instancié que si GetFirstItemWithDefault() est appelé.Ne vous inquiétez donc pas non plus de l'allocation redondante.

Le seul souci est de fournir un constructeur par défaut à tout le ItemType car l'objet static dépendra de manière générique du constructeur par défaut (dont vous devez déjà vous soucier, je suppose).Voilà.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top