new în C++

Creează un obiect în memoria dinamică (heap) și returnează un pointer la el; obiectul trăiește până este distrus explicit cu delete.

Sintaxă
T* p = new T(argumente);   // un obiect
T* t = new T[n];           // un tablou
// eliberare: delete p; delete[] t;

Ce face new

Variabilele obișnuite dispar automat la sfârșitul blocului. Un obiect creat cu new stă în memoria dinamică (heap) și trăiește până când îl distrugi cu delete, indiferent de bloc. new alocă memoria, apelează constructorul și îți dă adresa.

Pentru un tablou cu mărime aflată la rulare există new T[n], care trebuie eliberat cu delete[]. Dacă nu mai este memorie, new aruncă excepția std::bad_alloc (varianta new (std::nothrow) T returnează nullptr).

În C++ modern, new scris direct este rar: folosește std::make_unique<T>(...) (sau std::make_shared) pentru obiecte și std::vector pentru tablouri. Acestea eliberează singure memoria, deci nu poți uita delete.

Exemple

Exemplul 1: Obiect și tablou cu new

Fiecare new are perechea lui: delete pentru obiect, delete[] pentru tablou.

#include <print>
#include <string>

struct Client {
    std::string nume;
    int puncte;
};

int main() {
    Client* c = new Client{"Ana", 120};
    c->puncte += 30;
    std::println("{} are {} puncte", c->nume, c->puncte);
    delete c;

    int n = 4;
    int* temperaturi = new int[n]{18, 21, 19, 23};
    int suma = 0;
    for (int i = 0; i < n; ++i) suma += temperaturi[i];
    std::println("Media: {}", suma / n);
    delete[] temperaturi;
}

Rezultat

Ana are 150 puncte
Media: 20

Exemplul 2: Varianta modernă: make_unique și vector

Același program, fără niciun delete: memoria este eliberată automat la ieșirea din main.

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

struct Client {
    std::string nume;
    int puncte;
};

int main() {
    auto c = std::make_unique<Client>(Client{"Ana", 120});
    c->puncte += 30;
    std::println("{} are {} puncte", c->nume, c->puncte);

    std::vector<int> temperaturi = {18, 21, 19, 23};
    int suma = 0;
    for (int t : temperaturi) suma += t;
    std::println("Media: {}", suma / static_cast<int>(temperaturi.size()));
}

Rezultat

Ana are 150 puncte
Media: 20

Exemplul 3: Lipsa memoriei: std::bad_alloc

Cerem intenționat o cantitate imposibilă de memorie; new aruncă std::bad_alloc, pe care îl prindem.

#include <cstddef>
#include <new>
#include <print>

int main() {
    std::size_t imens = static_cast<std::size_t>(1) << 62;
    try {
        char* p = new char[imens];
        delete[] p;
    } catch (const std::bad_alloc&) {
        std::println("Nu există atâta memorie: std::bad_alloc");
    }
}

Rezultat

Nu există atâta memorie: std::bad_alloc

Greșeli frecvente

  • Uiți delete (sau ieși din funcție printr-o excepție înainte de el). Memoria rămâne ocupată până la sfârșitul programului: scurgere de memorie (memory leak). Folosește std::unique_ptr.
  • Eliberezi un tablou cu delete în loc de delete[] (sau invers). Este comportament nedefinit.
  • Scrii new pentru obiecte care ar putea fi simple variabile locale (Client* c = new Client; folosit doar în funcție). Variabila locală Client c; este mai rapidă și se distruge singură.

Comenzi înrudite

  • delete: Distruge un obiect creat cu new și eliberează memoria; scris ca = delete, interzice folosirea unei funcții.
  • pointeri (*, &): Un pointer este o variabilă care ține adresa altei variabile; prin el poți citi și modifica valoarea de la acea adresă.
  • nullptr: Valoarea unui pointer care nu arată spre nimic; înlocuiește vechile NULL și 0.
  • try, catch: try marchează codul care poate arunca o excepție, iar blocurile catch prind și tratează excepțiile de un anumit tip.
  • std::make_unique: Creează un obiect pe heap și returnează un std::unique_ptr care îl deține.
  • std::unique_ptr: Pointer inteligent care deține singur un obiect și îl șterge automat când iese din domeniu.