În ghidul oficial de bune practici C++ Core Guidelines (coordonat de Bjarne Stroustrup și Herb Sutter), prima și cea mai importantă regulă este simplă: nu utilizați niciodată manual operatorii new și delete în codul de aplicație. Alocarea manuală este principala cauză a scurgerilor de memorie (Memory Leaks), a accesărilor de memorie eliberată (Use-After-Free) și a eliberărilor duble (Double Free). C++-ul modern rezolvă definitiv aceste probleme prin pointeri inteligenți bazați pe principiul RAII (Resource Acquisition Is Initialization).
1. std::unique_ptr: Deținere Exclusivă cu Cost Zero (Zero-Overhead)
std::unique_ptr reprezintă proprietatea unică și exclusivă asupra unui obiect de pe heap. Nu poate fi copiat (copy constructorul este șters), dar poate fi mutat (moved) prin std::move. Dimensiunea sa în memorie este exact egală cu dimensiunea unui pointer brut (8 octeți pe arhitecturi 64-bit), oferind viteză nativă absolută:
#include <memory>
#include <print>
struct ConexiuneBazaDate {
ConexiuneBazaDate() { std::println("Conexiune deschisa."); }
~ConexiuneBazaDate() { std::println("Conexiune inchisa automat!"); }
void executaInterogare() { std::println("Interogare SQL rulata."); }
};
void proceseaza() {
// 1. Creare sigură dintr-un singur apel cu std::make_unique:
auto db = std::make_unique<ConexiuneBazaDate>();
db->executaInterogare();
// 2. Transfer de proprietate către o altă funcție sau variabilă:
auto altDb = std::move(db); // 'db' devine nullptr, 'altDb' deține resursa!
// LA IEȘIREA DIN BLOC: Destructorul este apelat automat, memoria este eliberată!
}
2. std::shared_ptr și std::weak_ptr: Deținere Partajată
Dacă o resursă trebuie să fie partajată între multiple subsisteme și nu este clar cine va termina ultimul lucrul cu ea, se utilizează std::shared_ptr, care menține un contor atomic de referințe (Reference Count):
- Fiecare copiere a pointerului incrementează contorul.
- Fiecare distrugere a unei instanțe decrementează contorul.
- Când contorul ajunge la zero, obiectul de pe heap este distrus instantaneu.
shared_ptr către Obiectul B, iar Obiectul B deține un shared_ptr către Obiectul A, contorul nu va ajunge niciodată la zero, generând o scurgere permanentă de memorie! Soluția este transformarea uneia dintre referințe în std::weak_ptr (o referință slabă care observă obiectul fără a-i incrementa contorul de proprietate).
3. Regula celor Cinci (Rule of Five)
Dacă o clasă gestionează manual o resursă brută de sistem de nivel scăzut, trebuie să implementați explicit (sau să ștergeți cu = delete) toate cele 5 funcții speciale ale ciclului de viață:
class ResursaCustom {
public:
// 1. Destructor
~ResursaCustom() noexcept;
// 2. Constructor de copiere (Copy Constructor)
ResursaCustom(const ResursaCustom& other);
// 3. Operator de atribuire prin copiere (Copy Assignment)
ResursaCustom& operator=(const ResursaCustom& other);
// 4. Constructor de mutare (Move Constructor - noexcept obligatoriu!)
ResursaCustom(ResursaCustom&& other) noexcept;
// 5. Operator de atribuire prin mutare (Move Assignment)
ResursaCustom& operator=(ResursaCustom&& other) noexcept;
};