std::enable_shared_from_this în C++

Clasă de bază care permite unui obiect deținut de shared_ptr să obțină un shared_ptr către el însuși.

Sintaxă
class T : public std::enable_shared_from_this<T> { ... };
std::shared_ptr<T> shared_from_this();

Ce face std::enable_shared_from_this

Uneori o metodă trebuie să dea altcuiva un shared_ptr către obiectul curent (de exemplu se înregistrează într-o listă). std::shared_ptr<T>(this) ar crea un al doilea contor și obiectul ar fi șters de două ori.

Soluția: clasa moștenește std::enable_shared_from_this<T>, iar în metode apelezi shared_from_this(). Primești un shared_ptr care împarte contorul cu cei existenți.

Funcționează doar dacă obiectul este deja deținut de un shared_ptr (creat de obicei cu std::make_shared). Altfel, din C++17, se aruncă std::bad_weak_ptr.

Ce returnează

shared_from_this() returnează un std::shared_ptr<T> care împarte proprietatea cu ceilalți.

Exemple

Exemplul 1: Un abonat care se înregistrează singur

#include <memory>
#include <print>
#include <string>
#include <vector>

struct Abonat;
std::vector<std::shared_ptr<Abonat>> lista;

struct Abonat : std::enable_shared_from_this<Abonat> {
    std::string nume;
    explicit Abonat(std::string n) : nume(std::move(n)) {}
    void inscrie() { lista.push_back(shared_from_this()); }
};

int main() {
    auto ana = std::make_shared<Abonat>("Ana");
    ana->inscrie();

    std::println("În listă: {}", lista[0]->nume);
    std::println("proprietari: {}", ana.use_count());
}

Rezultat

În listă: Ana
proprietari: 2

Exemplul 2: Obiect care nu este deținut de shared_ptr

Pe un obiect obișnuit (pe stivă), shared_from_this() aruncă std::bad_weak_ptr.

#include <memory>
#include <print>

struct Nod : std::enable_shared_from_this<Nod> {};

int main() {
    Nod n;
    try {
        auto p = n.shared_from_this();
    } catch (const std::bad_weak_ptr& e) {
        std::println("Eroare: {}", e.what());
    }
}

Rezultat

Eroare: bad_weak_ptr

Greșeli frecvente

  • Moștenești enable_shared_from_this privat (de exemplu cu class fără public). Mecanismul nu mai funcționează; moștenirea trebuie să fie publică.
  • Apelezi shared_from_this() în constructor. În acel moment obiectul nu este încă deținut de niciun shared_ptr.

Comenzi înrudite

  • std::shared_ptr: Pointer inteligent cu proprietate comună: obiectul este șters când ultimul shared_ptr dispare.
  • std::weak_ptr: Referință slabă la un obiect deținut de shared_ptr: nu îl ține în viață; lock() îl folosește în siguranță.
  • this: Pointer către obiectul curent, disponibil în orice metodă nestatică a unei clase.