Essayer de collecter quelques utilisations:
Liaison de certains temporaires à reference-to-const, pour allonger sa durée de vie. La référence peut être une base - et son destructeur n'a pas besoin d'être virtuel - le bon destructeur est toujours appelé:
ScopeGuard const& guard = MakeGuard(&cleanUpFunction);
Explication , en utilisant le code:
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); }
Cette astuce est utilisée dans la classe utilitaire ScopeGuard d'Alexandrescu. Une fois que le temporaire est hors de portée, le destructeur de Derived est appelé correctement. Le code ci-dessus manque quelques petits détails, mais c'est le gros problème.
Utilisez const pour indiquer aux autres méthodes de ne pas modifier l'état logique de cet objet.
struct SmartPtr {
int getCopies() const { return mCopiesMade; }
};
Utilisez const pour les classes de copie sur écriture , pour que le compilateur vous aide à décider quand et quand vous devez copier.
struct MyString {
char * getData() { /* copy: caller might write */ return mData; }
char const* getData() const { return mData; }
};
Explication : Vous souhaiterez peut-être partager des données lorsque vous copiez quelque chose tant que les données de l'objet d'origine et de l'objet copié restent les mêmes. Une fois que l'un des objets change de données, vous avez cependant besoin de deux versions: une pour l'original et une pour la copie. Autrement dit, vous copiez sur une écriture dans l'un ou l'autre objet, de sorte qu'ils aient maintenant tous les deux leur propre version.
Utilisation du code :
int main() {
string const a = "1234";
string const b = a;
// outputs the same address for COW strings
cout << (void*)&a[0] << ", " << (void*)&b[0];
}
L'extrait de code ci-dessus imprime la même adresse sur mon GCC, car la bibliothèque C ++ utilisée implémente une copie sur écriture std::string
. Les deux chaînes, même s'il s'agit d'objets distincts, partagent la même mémoire pour leurs données de chaîne. Faire b
non-const préférera la version non-const de operator[]
et GCC créera une copie du tampon de la mémoire de sauvegarde, car nous pourrions le changer et cela ne doit pas affecter les données de a
!
int main() {
string const a = "1234";
string b = a;
// outputs different addresses!
cout << (void*)&a[0] << ", " << (void*)&b[0];
}
Pour que le constructeur de copie fasse des copies à partir des objets const et des temporaires :
struct MyClass {
MyClass(MyClass const& that) { /* make copy of that */ }
};
Pour créer des constantes qui ne peuvent pratiquement pas changer
double const PI = 3.1415;
Pour passer des objets arbitraires par référence plutôt que par valeur - pour éviter le passage par valeur éventuellement coûteux ou impossible
void PrintIt(Object const& obj) {
// ...
}