Intentando recopilar algunos usos:
Enlazar algunos temporales a referencia a constante, para alargar su vida útil. La referencia puede ser una base, y su destructor no necesita ser virtual, el destructor correcto todavía se llama:
ScopeGuard const& guard = MakeGuard(&cleanUpFunction);
Explicación , usando el 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); }
Este truco se usa en la clase de utilidad ScopeGuard de Alexandrescu. Una vez que el temporal sale del alcance, el destructor de Derived se llama correctamente. El código anterior pierde algunos pequeños detalles, pero ese es el gran problema.
Use const para decirle a otros que los métodos no cambiarán el estado lógico de este objeto.
struct SmartPtr {
int getCopies() const { return mCopiesMade; }
};
Use const para las clases de copiar y escribir , para que el compilador lo ayude a decidir cuándo y cuándo no necesita copiar.
struct MyString {
char * getData() { /* copy: caller might write */ return mData; }
char const* getData() const { return mData; }
};
Explicación : es posible que desee compartir datos cuando copie algo, siempre y cuando los datos del objeto original y el copiado sigan siendo los mismos. Una vez que uno de los objetos cambia los datos, ahora necesita dos versiones: una para el original y otra para la copia. Es decir, copia en una escritura a cualquiera de los objetos, de modo que ahora ambos tengan su propia versión.
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];
}
El fragmento anterior imprime la misma dirección en mi GCC, porque la biblioteca C ++ utilizada implementa una copia en escritura std::string
. Ambas cadenas, aunque son objetos distintos, comparten la misma memoria para sus datos de cadena. Hacer b
no const preferirá la versión sin const del operator[]
GCC y creará una copia del búfer de memoria de respaldo, porque podríamos cambiarlo y no debe afectar los datos de a
!
int main() {
string const a = "1234";
string b = a;
// outputs different addresses!
cout << (void*)&a[0] << ", " << (void*)&b[0];
}
Para que el constructor de copias haga copias de objetos constantes y temporales :
struct MyClass {
MyClass(MyClass const& that) { /* make copy of that */ }
};
Para hacer constantes que trivialmente no pueden cambiar
double const PI = 3.1415;
Para pasar objetos arbitrarios por referencia en lugar de por valor , para evitar el paso por valor posiblemente costoso o imposible
void PrintIt(Object const& obj) {
// ...
}