È possibile avere una variabile membro statica nella mia classe modello, senza che l'utente della classe debba saperlo?

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

Domanda

Ho una classe di container modello, qualcosa di simile a questo codice giocattolo:

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

Questa classe è davvero conveniente da usare: qualsiasi codice può solo #Includere "myvector.h" e quindi iniziare a dichiarare oggetti di tipo myvector e myvector e così via, e tutto funziona solo (TM) senza alcun futzing in giro richiesto.

Una cosa che mi dà fastidio, tuttavia, è la presenza della variabile membro _DefaultItem, che è lì solo per dare a getFirstemWithDefault () la possibilità di restituire un riferimento valido quando il contenitore è vuoto. L'obiezione è che se dichiaro oggetti myvector, ciò significa che anche le copie di _defaultItem saranno presenti nella RAM --- anche se sono tutte identiche e di sola lettura, e quindi è necessario solo essere solo uno per Processo, non uno per myvector.

Quindi, la soluzione ovvia è rendere statica _defaultItem .... ma afaict che ha un costo: se lo faccio, non è più possibile che nessun vecchio codice di codice sia semplicemente #include "myvector.h" e vai. .. Ora l'utente deve essere sicuro di dichiarare l'archiviazione per quella variabile statica in uno dei suoi file .cpp, che è (a) un dolore nel calcio e (b) significa che l'utente del codice deve essere consapevole dei dettagli dell'implementazione interna della classe. Poiché _DefaultItem è una variabile di membro privato, l'utente della classe non dovrebbe pensarci o addirittura rendersi conto che esiste, per non parlare di sapere che deve dichiarare l'archiviazione per questo. (E se due pezzi di codice separati dichiarassero entrambi gli archivi per esso, ognuno non sapendo l'altro ha fatto la stessa cosa? Ciò non causerebbe un errore di linker del simbolo duplicato?)

Pertanto, la mia domanda è: esiste un modo per dire a C ++ di fornire automaticamente una memoria unica (per tipo di myvector istanziato) per questa variabile membro statica, in modo che gli utenti di Myvector non debbano saperlo? (Si noti che dovrebbe essere automatico per tutte le possibili istanziazioni di MyVector <...>, non solo per alcuni casi comuni)

È stato utile?

Soluzione

Se è un modello, il compilatore farà la magia per te. Basta mettere il membro statico nell'intestazione e il compilatore vedrà che è appena istanziato una volta.

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


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

Altri suggerimenti

Perché non fare quell'elemento predefinito locale statico alla funzione?

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

Questo potrebbe non essere quello che vuoi se vuoi controllare di nuovo contro l'elemento predefinito in qualche altra funzione, ma per questo puoi semplicemente metterlo in una funzione separata (che potrebbe essere statica stessa):

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

E chiamare quella funzione quando è necessario accedere all'elemento predefinito.


Detto questo, penso che avere un oggetto predefinito non sia davvero bello. std::vector Inoltre non ce l'ha e non ne ha bisogno. Dì solo all'utente di verificare se il vettore lo è empty ed essere fatto. Un problema con la statica nascosta è che non lo sai ItemType. Potrebbe essere una classe che mangia tonnellate di risorse e ne hai appena fatto un'altra istanza! Forse ripensare a quella classe di design e dopo quello, passa a a std::vector. :)

Quindi, la soluzione ovvia è rendere statica _defaultItem .... ma afaict che comporta un costo: se lo faccio, non è più possibile che nessun vecchio codice di codice sia semplicemente #include "myarray.h" e vai. .. Ora l'utente deve essere sicuro di dichiarare l'archiviazione per quella variabile statica in uno dei suoi file .cpp, che è (a) un dolore

No. Questa paura è per preoccupazione. In templates puoi (must) dichiarare il static variabile nello stesso file.

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

Inoltre, nota che questo static il membro sarà istanziato solo se GetFirstItemWithDefault() è chiamato. Quindi non preoccuparti anche dell'allocazione ridondante.

L'unica cosa che preoccupa è di Fornire costruttore predefinito a tutti i ItemType come la static L'oggetto si baserà genericamente sul costruttore predefinito (che devi già preoccuparti, immagino). Questo è tutto.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top