Question

Disons que j'ai une 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_;
}

Si insert() ajoute un élément à easySet_. Les membres de difficultSet_ changent en fonction des membres de easySet_.

Le problème que j'ai est que, plusieurs insertions signifie que difficultSet_ est recalculée en permanence. Je veux donc difficultSet_ à calculer paresseusement (à savoir que lorsque sont appelés difficultBegin(), difficultEnd() ou difficultSize()). Le problème est, alors je dois en fait de faire difficultSet_ dans un mutable car sinon difficultSize() ne peut pas fonctionner sur elle.

Alors maintenant ma déclaration de classe ressemble

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

Je me sens comme cela est une mauvaise conception bien. Y at-il une meilleure façon?

Était-ce utile?

La solution

C'est tout à fait la façon de le faire. Const peut signifier const binaire, ou cela peut signifier const sur le plan conceptuel. L'utilisation mutable signifie que vous faites le plus tard, ce qui est bien.

Autres conseils

Pour aider à comprendre pourquoi utiliser mutable, nous pouvons explorer d'autres options.

Vous pouvez résoudre le même problème en utilisant const_cast :

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

Après avoir offert cette solution, je dirai que c'est inférieur à l'aide de mutable . Si un membre est marqué comme mutable , puis simplement en regardant l'en-tête que je peux comprendre comment vous traiter. Je ne comprends pas ces informations si vous utilisez const_cast .

Mais quelqu'un peut prendre l'autre côté du débat, et dire qu'il est préférable de ne pas exposer les détails de mise en œuvre dans l'en-tête.

Ceci est essentiellement la raison pour laquelle C ++ a la construction mutable. Alan De Smet de diatribe sur l'utilisation abusive de mutable montre les types de situations dans lesquelles mutable ne doit pas être utilisé.

ne change pas ce que l'NumberCollection représente Dans ce cas, difficultSize () - qui convient pour le marquage const. Il fait comment jamais besoin de changer les entrailles parfois, ce qui est la raison pour laquelle vous devez marquer difficultSet_ et upToDate_ mutable.

Votre solution est bien dans 98 C ++. Notez que dans 11 C ++, vous devriez envisager de synchroniser l'accès à vos données mutables. Sinon, vous pouvez rencontrer des problèmes lorsque vous votre classe est utilisée par le TSL, ce qui suppose que toutes les fonctions membres const sont thread-safe.

Pour plus de détails, voir Est-ce que const signifie thread-safe en C ++ 11?

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