delete în C++

Memorie, pointeri și referințe C++98 (= delete: C++11)

Distruge un obiect creat cu new și eliberează memoria; scris ca = delete, interzice folosirea unei funcții.

Sintaxă
delete p;           // distruge un obiect creat cu new
delete[] t;         // distruge un tablou creat cu new[]
void f(double) = delete;   // C++11: interzice o funcție

Ce face delete

delete p; apelează destructorul obiectului spre care arată p și eliberează memoria alocată de new. Pentru tablourile create cu new T[n] se folosește delete[]. După delete, pointerul are încă adresa veche, dar memoria nu mai este a ta; setează-l la nullptr. delete nullptr; nu face nimic, deci este sigur.

A doua folosire, din C++11: = delete după declarația unei funcții o face „ștearsă”. Orice apel al ei dă eroare de compilare. Se folosește pentru a interzice copierea unei clase (Clasa(const Clasa&) = delete;) sau anumite conversii (de exemplu apelul cu double al unei funcții care trebuie să primească int).

Exemple

Exemplul 1: delete apelează destructorul

#include <print>

struct Fisier {
    Fisier() { std::println("deschid fișierul"); }
    ~Fisier() { std::println("închid fișierul"); }
};

int main() {
    Fisier* f = new Fisier;
    std::println("lucrez cu fișierul");
    delete f;
    f = nullptr;
    delete f;  // delete pe nullptr nu face nimic
    std::println("gata");
}

Rezultat

deschid fișierul
lucrez cu fișierul
închid fișierul
gata

Exemplul 2: = delete: funcții interzise

seteaza_varsta(20.5) nu s-ar compila, pentru că varianta cu double este ștearsă (fără ea, 20.5 ar fi fost transformat în tăcere în 20). La fel, o copie a lui Token nu s-ar compila.

#include <print>
#include <string>
#include <utility>

void seteaza_varsta(int ani) { std::println("Vârsta: {}", ani); }
void seteaza_varsta(double) = delete;

class Token {
public:
    explicit Token(std::string cod) : cod_(std::move(cod)) {}
    Token(const Token&) = delete;
    Token& operator=(const Token&) = delete;
    const std::string& cod() const { return cod_; }
private:
    std::string cod_;
};

int main() {
    seteaza_varsta(20);
    Token t("A1B2");
    std::println("Token: {}", t.cod());
    // seteaza_varsta(20.5);  // eroare: funcție ștearsă
    // Token copie = t;       // eroare: copierea este ștearsă
}

Rezultat

Vârsta: 20
Token: A1B2

Greșeli frecvente

  • Apelezi delete de două ori pe același pointer (double free) sau folosești obiectul după delete (use after free). Ambele sunt comportament nedefinit și cauze frecvente de erori grave de securitate.
  • Folosești delete pe un pointer care nu vine de la new (adresa unei variabile locale, rezultatul lui malloc). Comportament nedefinit.
  • Folosești delete în loc de delete[] pentru un tablou creat cu new[].

Comenzi înrudite

  • new: Creează un obiect în memoria dinamică (heap) și returnează un pointer la el; obiectul trăiește până este distrus explicit cu delete.
  • 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.
  • class: Definește un tip nou care grupează date (membri) și funcțiile care lucrează cu ele (metode); baza programării orientate pe obiecte.
  • std::unique_ptr: Pointer inteligent care deține singur un obiect și îl șterge automat când iese din domeniu.