Lidar com computação preguiçoso em classes C ++
-
22-08-2019 - |
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?
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?