Domanda

Diciamo che ho una classe:

class NumberCollection
{
public:
    typedef std::set<int> SetType;
    typedef SetType::iterator iterator;
    void insert(int n);

    iterator begin();
    iterator end();
    size_t size() const;

    iterator difficultBegin();
    iterator difficultEnd();
    size_t difficultSize() const;    

private:
    SetType easySet_, difficultSet_;
}

Dove insert() aggiunge un elemento alla easySet_. i membri di difficultSet_ cambiano a seconda dei membri del easySet_.

Il problema che sto avendo è che, più inserimenti significa che difficultSet_ viene costantemente ricalcolato. Quindi voglio difficultSet_ da calcolare pigramente (vale a dire, solo quando difficultBegin(), difficultEnd() o difficultSize() sono chiamati). Il problema è, quindi io in realtà deve fare difficultSet_ in un mutable perché altrimenti difficultSize() non può operare su di esso.

Così ora la mia dichiarazione di classe appare come

class NumberCollection
{
public:
    typedef std::set<int> SetType;
    typedef SetType::iterator iterator;
    void insert(int n);

    iterator begin();
    iterator end();
    size_t size() const;

    iterator difficultBegin();
    iterator difficultEnd();
    size_t difficultSize() const;    

private:
    SetType easySet_; 
    mutable SetType difficultSet_;
    mutable bool upToDate_;
}

Mi sento come se questa è la cattiva progettazione però. C'è un modo migliore?

È stato utile?

Soluzione

Questo è totalmente il modo per farlo. Const può significare const binario, o può significare const concettualmente. Utilizzando mutabili significa che stai facendo più tardi, che va bene.

Altri suggerimenti

Per aiutare a capire perché utilizzare mutevole, siamo in grado di esplorare altre opzioni.

È possibile risolvere lo stesso problema usando const_cast :

size_t NumberCollection::difficultSize() const
{
     if(!upToDate_)
     {
          NumberCollection& nonConst = const_cast<NumberCollection&>(*this);
          nonConst.difficultSet_ = PerformExpensiveCalculationFunction();
          nonConst.upToDate_ = true;
     }
     // etc....
}

Dopo aver offerto questa soluzione, io dico che è inferiore a usando mutevole . Se un membro è contrassegnato come mutevole , poi semplicemente guardando l'intestazione ho potuto capire come si sta trattando. Non capisco queste informazioni se si utilizza const_cast .

Ma allora qualcuno potrebbe prendere l'altro lato del dibattito, e dire che è meglio non esporre i dettagli di implementazione nell'intestazione.

Questo è essenzialmente il motivo C ++ ha il costrutto mutevole. di sproloquio circa l'abuso di mutabile Alan De Smet mostra i tipi di situazioni in cui mutevole non dovrebbe essere usato.

In questo caso, difficultSize () non cambia ciò che il NumberCollection rappresenta - che è adatto per la marcatura come const. Lo fa come mai bisogno di cambiare la struttura interna, a volte, è per questo che è necessario marcare difficultSet_ e upToDate_ come mutevole.

La soluzione va bene in C ++ 98. Si noti che in C ++ 11 si dovrebbe considerare di sincronizzare l'accesso ai propri dati mutabili. In caso contrario, si può incorrere in problemi quando si la classe è utilizzata dal STL, che presuppone che tutte le funzioni membro const sono thread-safe.

Per ulteriori informazioni, vedere Ha const significa thread-safe in C ++ 11?

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