Tentando coletar alguns usos:
Vinculando alguns temporários à referência à const, para prolongar sua vida útil. A referência pode ser uma base - e o destruidor dela não precisa ser virtual - o destruidor certo ainda é chamado:
ScopeGuard const& guard = MakeGuard(&cleanUpFunction);
Explicação , usando o código:
struct ScopeGuard {
~ScopeGuard() { } // not virtual
};
template<typename T> struct Derived : ScopeGuard {
T t;
Derived(T t):t(t) { }
~Derived() {
t(); // call function
}
};
template<typename T> Derived<T> MakeGuard(T t) { return Derived<T>(t); }
Esse truque é usado na classe de utilitário ScopeGuard do Alexandrescu. Depois que o temporário fica fora do escopo, o destruidor de Derivado é chamado corretamente. O código acima perde alguns pequenos detalhes, mas esse é o grande problema.
Use const para dizer aos outros que os métodos não mudarão o estado lógico desse objeto.
struct SmartPtr {
int getCopies() const { return mCopiesMade; }
};
Use const para copiar-na-gravar classes , para fazer o compilador ajudá-lo a decidir quando e quando você não precisa copiar.
struct MyString {
char * getData() { /* copy: caller might write */ return mData; }
char const* getData() const { return mData; }
};
Explicação : Você pode compartilhar dados quando copiar algo, desde que os dados do objeto original e do objeto copiado permaneçam os mesmos. Depois que um dos objetos altera os dados, você precisa agora de duas versões: uma para o original e outra para a cópia. Ou seja, você copia em uma gravação para qualquer um dos objetos, para que agora ambos tenham sua própria versão.
Usando código :
int main() {
string const a = "1234";
string const b = a;
// outputs the same address for COW strings
cout << (void*)&a[0] << ", " << (void*)&b[0];
}
O trecho acima imprime o mesmo endereço no meu GCC, porque a biblioteca C ++ usada implementa uma cópia na gravação std::string
. As duas cadeias, mesmo que sejam objetos distintos, compartilham a mesma memória para seus dados. Tornar b
não-const preferirá a versão não-const do operator[]
e o GCC criará uma cópia do buffer de memória de backup, porque podemos alterá-lo e não deve afetar os dados de a
!
int main() {
string const a = "1234";
string b = a;
// outputs different addresses!
cout << (void*)&a[0] << ", " << (void*)&b[0];
}
Para que o construtor de cópias faça cópias de objetos const e temporários :
struct MyClass {
MyClass(MyClass const& that) { /* make copy of that */ }
};
Por fazer constantes que trivialmente não podem mudar
double const PI = 3.1415;
Para passar objetos arbitrários por referência em vez de por valor - para impedir a passagem por valor possivelmente cara ou impossível
void PrintIt(Object const& obj) {
// ...
}