Pergunta

Vamos dizer que eu tenho uma 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_;
}

Onde insert() adiciona um elemento à easySet_. membros do difficultSet_ mudam de acordo com os membros da easySet_.

O problema que estou tendo é que, vários meios inserções que difficultSet_ é constantemente recalculado. Então, eu quero difficultSet_ a ser calculado preguiçosamente (ou seja, somente quando difficultBegin(), difficultEnd(), ou difficultSize() são chamados). O problema é, então eu realmente tenho que fazer difficultSet_ em um mutable porque senão difficultSize() não pode operá-lo.

Então, agora meus declaração de classe parece com

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

Eu sinto que este é design ruim embora. Existe uma maneira melhor?

Foi útil?

Solução

Isso é totalmente a maneira de fazê-lo. Const pode significar const binário, ou pode significar conceitualmente const. Usando meios mutáveis ??você está fazendo a tarde, o que é bom.

Outras dicas

Para ajudar a entender por que usar mutável, podemos explorar outras opções.

Você pode resolver o mesmo problema usando const_cast :

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

Depois de ter oferecido esta solução, eu vou dizer que é inferior ao uso de mutável . Se um membro é marcado como mutável , em seguida, simplesmente olhando para o cabeçalho eu possa reunir como você está tratando-o. Eu não obter essa informação se você usar const_cast .

Mas alguém, em seguida, pode tomar o outro lado do debate, e dizer que não é melhor para expor detalhes de implementação no cabeçalho.

Esta é essencialmente a razão C ++ tem a construo mutável. do discurso sobre o uso indevido de shows mutáveis ??Alan De Smet os tipos de situações em que mutável não deve ser utilizado.

Neste caso, difficultSize () não muda o que o NumberCollection representa - o que é adequado para a marcação como const. Ele faz como precisar alterar os internos, às vezes, é por isso que você precisa para marcar difficultSet_ e upToDate_ como mutável.

A sua solução é bom em C ++ 98. Note-se que em C ++ 11 você deve considerar sincronizar o acesso a seus dados mutáveis. Caso contrário, você pode ter problemas quando sua classe é usada pelo STL, que assume que todas as funções de membro const são thread-safe.

Para mais detalhes, consulte Does const média thread-safe em C ++ 11?

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top