Ce face std::unique_ptr
std::unique_ptr înlocuiește perechea new/delete. Ține adresa unui obiect alocat dinamic și îl distruge automat (apelează delete) când pointerul iese din domeniu, chiar dacă între timp a apărut o excepție. Nu mai poți uita să eliberezi memoria.
Este „unic”: un singur unique_ptr deține obiectul la un moment dat. Nu se poate copia, dar se poate muta cu std::move; după mutare, pointerul vechi devine gol (nullptr). Nu costă nimic în plus față de un pointer obișnuit.
Se creează aproape mereu cu std::make_unique. Accesul la obiect se face ca la un pointer: *p și p->membru. Într-un if, pointerul este adevărat dacă deține ceva.
Ce returnează
Un obiect care deține pointerul. Se folosește cu *, ->, get(), reset(), release().
Exemple
Exemplul 1: Obiectul este distrus automat
Destructorul clasei afișează un mesaj, ca să vezi exact când este șters obiectul: la ieșirea din blocul în care a fost creat pointerul.
#include <memory>
#include <print>
#include <string>
struct Fisier {
std::string nume;
explicit Fisier(std::string n) : nume(std::move(n)) { std::println("Deschid {}", nume); }
~Fisier() { std::println("Închid {}", nume); }
};
int main() {
{
auto f = std::make_unique<Fisier>("note.txt");
std::println("Lucrez cu {}", f->nume);
} // aici f iese din domeniu și obiectul este șters
std::println("După bloc");
}
Rezultat
Deschid note.txt
Lucrez cu note.txt
Închid note.txt
După bloc
Exemplul 2: Transferul proprietății cu std::move
Un unique_ptr nu se copiază. Cu std::move, obiectul trece la alt pointer, iar cel vechi rămâne gol.
#include <memory>
#include <print>
#include <utility>
int main() {
std::unique_ptr<int> a = std::make_unique<int>(42);
std::unique_ptr<int> b = std::move(a); // auto b = a; nu compilează
std::println("a este gol: {}", a == nullptr);
std::println("b = {}", *b);
}
Rezultat
a este gol: true
b = 42
Exemplul 3: Polimorfism: un vector de figuri
Un std::vector<std::unique_ptr<Baza>> ține obiecte de tipuri derivate diferite. La sfârșitul programului toate sunt șterse automat.
#include <memory>
#include <print>
#include <vector>
struct Figura {
virtual ~Figura() = default;
virtual double arie() const = 0;
};
struct Patrat : Figura {
double l;
explicit Patrat(double latura) : l(latura) {}
double arie() const override { return l * l; }
};
struct Dreptunghi : Figura {
double a, b;
Dreptunghi(double x, double y) : a(x), b(y) {}
double arie() const override { return a * b; }
};
int main() {
std::vector<std::unique_ptr<Figura>> figuri;
figuri.push_back(std::make_unique<Patrat>(3));
figuri.push_back(std::make_unique<Dreptunghi>(2, 5));
for (const auto& f : figuri) {
std::println("Arie: {}", f->arie());
}
}
Rezultat
Arie: 9
Arie: 10
Greșeli frecvente
- Încerci să copiezi un
unique_ptr(de exemplu îl dai prin valoare unei funcții fărăstd::move). Eroarea de compilare spune că constructorul de copiere este șters (deleted). - Folosești pointerul după
std::move. Pointerul vechi estenullptr, iar*ppe el este comportament nedefinit. - Clasa de bază nu are destructor
virtual. Ștergerea unui obiect derivat printr-ununique_ptr<Baza>nu mai apelează destructorul derivat.
Comenzi înrudite
std::make_unique: Creează un obiect pe heap și returnează un std::unique_ptr care îl deține.std::unique_ptr::reset: reset șterge obiectul deținut (și poate prelua altul); release renunță la proprietate fără să șteargă.std::unique_ptr::get: Returnează pointerul brut către obiectul deținut, fără să renunțe la proprietate.std::shared_ptr: Pointer inteligent cu proprietate comună: obiectul este șters când ultimul shared_ptr dispare.std::move: Mută elementele unui interval la o destinație, fără să le copieze (versiunea din <algorithm>).pointeri (*, &): Un pointer este o variabilă care ține adresa altei variabile; prin el poți citi și modifica valoarea de la acea adresă.