Les smarts pointers avec C++11

cpp

Pour aider à la gestion mémoire (dynamique) le C++11 a introduit des smarts pointeurs. Grâce à cette technique, désormais plus besoin d’utiliser les smarts pointers de Boost ou d’autres issus de bibliothèques externes.

Rappel : Les smarts pointers sont destinés à pointer des objets du tas (ou heap), alloués avec les opérateurs new ou new[]. Il simplifie grandement vos programmes C++ en vous cachant l’opérateur delete. Ils sont très majoritairement alloués sur la pile.

C++11 propose les 3 modèles suivants :

unique_ptr qui est destiné à pointer un objet de manière unique (relation de 1 à 1).

shared_ptr qui est destiné à partager un objet entre plusieurs smarts pointers : plusieurs shared_ptr peuvent pointer un même objet. Il possède un compteur de référence.

weak_ptr est un smart pointer qui n’agit pas sur l’objet pointé : n’agit pas sur le compteur de référence et n’essaye pas de détruite l’objet pointé.

unique_ptr

Il est destiné à des cycles de vie court. Il est le seul à pointer l’objet. Son cycle de vie est généralement dans un scope de code.

class X {};
int main()
{
    unique_ptr<X> uniq1( new X() );
    // ...
    return 0;
} // fin de la vie de uniq1 l'opérateur delete sera appelé

Impossible d’utiliser le constructeur par copie et l’opérateur =

unique_ptr<X> uniq2( uniq1 ); // KO
unique_ptr<X> uniq3 = uniq1;  // KO
uniq2 = uniq3;                // KO

Interdit de faire pointer 2 unique_ptr sur le même objet : c’est le crash assuré !

    X * px = new X();
    unique_ptr<X> uniq3( px );
    unique_ptr<X> uniq4( px ); // KO l'objet est déjà pointé par uniq3

Bonne pratique : Si vous adoptez les smarts pointers, ne mélangez pas les pointeurs et les smarts pointers.

shared_ptr

Ce dernier est destiné au cas suivant : un objet alloué sur le tas serait pointé par plusieurs smarts pointers. Plus ambitieux que l’unique_ptr il possède un compteur référence et implémente le constructeur par copie et l’opérateur =.

int main() {
    shared_ptr<X> sp1( new X() ); // L'objet vient d'être crée,
                                  // le compteur est à 1
    shared_ptr<X> sp2( sp1 );     // 2 smarts pointers pointent
                                  // notre objet, compteur = 2
    shared_ptr<X> sp3;
    sp3 = sp1;                    // compteur = 3

    cout << sp3.use_count() << endl; // Le compteur est à 3 !
    return 0;
}

Trois smarts pointers pointent un objet. Les smarts pointers sont alloués sur la pile, seul le dernier smart pointeur vivant détruira l’objet et ce, grâce au compteur.

Le shared_ptr propose une méthode use_count() qui retourne l’état du compteur.

L’opérateur -> est surchargé dans les smarts pointers il permet d’accéder aux méthodes de l’objet pointé.

class X {
public:
    void foo() { cout << "foo" << endl; } };

int main() {
    shared_ptr<X> sp1( new X() );
    sp1->foo(); // opérateur ->

    return 0;
}

Les smarts pointers de C++11 propose la méthode reset() pour vider le smart pointer.

    // le compteur de sp3 = 3
    sp3.reset(); // -1  sur le compteur ici
    if( !sp3 ) {
        cout << "KO" << endl;
    }
    cout << sp3.use_count() << endl; // compteur = 2

L’opérateur ! (not) retourne la validité ou pas du smart pointer.

weak_ptr

C’est le smart pointer qui permet un pointage dit faible. Il n’a aucune action sur le cycle de vie de l’objet pointé. Il permet notamment de résoudre les problèmes de références cycliques.

// Le compteur de sp6 est à 3
weak_ptr<X> sp6( sp1 );
cout << sp6.use_count() << endl; // Ici le compteur est toujours à 3 !

Cet article est terminé n’hésitez-pas à le partager en cliquant sur les liens ci-dessous.

Catégories
0 Comments
0 Pings & Trackbacks

Laisser un commentaire