Memoria dinamica (new/delete)
Fa parte della sezione Programmazione orientata agli oggetti del percorso C++ di Coddy. Lezione 14 di 104.
Ora che hai capito i puntatori e i riferimenti, mettiamoli al lavoro con l'allocazione dinamica della memoria. Gli operatori new e delete ti permettono di creare e distruggere oggetti nell'heap durante l'esecuzione.
Usa new per allocare memoria e ottenere un puntatore ad essa:
int* num = new int; // Alloca un singolo intero
*num = 42; // Assegna un valore tramite il puntatore
Player* player = new Player("Hero"); // Alloca un oggettoOgni new deve avere un delete corrispondente per liberare la memoria:
delete num; // Libera un singolo oggetto
delete player; // Chiama il distruttore, poi libera la memoriaPer gli array, usa new[] e delete[]:
int* scores = new int[5]; // Alloca un array di 5 interi
scores[0] = 100;
delete[] scores; // Libera l'array - nota le parentesi quadre!Errori comuni da evitare:
// Perdita di memoria - si è dimenticato di usare delete
int* ptr = new int(10);
ptr = new int(20); // Accesso alla prima allocazione perso!
// Puntatore pendente - utilizzato dopo delete
delete ptr;
*ptr = 5; // Comportamento indefinito!
// delete non corrispondente
int* arr = new int[10];
delete arr; // Sbagliato! Si dovrebbe usare delete[]Dopo l’eliminazione, imposta i puntatori su nullptr per evitare riutilizzi accidentali. La gestione manuale della memoria è soggetta a errori, ed è per questo che il C++ moderno preferisce i puntatori intelligenti, che esploreremo nella prossima lezione.
Sfida
FacileCostruiamo un semplice sistema di archiviazione dei messaggi che dimostra l'allocazione dinamica della memoria con new e delete.
Creerai due file per organizzare il codice:
MessageBox.h: definisci una classeMessageBoxche gestisce dinamicamente un array di messaggi. La classe dovrebbe avere:- Un puntatore privato a un array di stringhe allocato dinamicamente
- Un intero privato che tiene traccia del numero corrente di messaggi
- Un intero privato che memorizza la capacità massima
- Un costruttore che accetta una capacità e alloca l'array usando
new[] - Un distruttore che libera correttamente la memoria usando
delete[]e stampa"MessageBox destroyed" - Un metodo
addMessage(string msg)che aggiunge un messaggio se c'è spazio, restituendotruein caso di successo ofalsese l'array è pieno - Un metodo
printAll()che stampa ogni messaggio memorizzato su una riga separata
main.cpp: leggi un valore di capacità e il numero di messaggi dall'input. Poi leggi altrettante stringhe di messaggio. Crea unMessageBoxnell'heap usandonew, aggiungici tutti i messaggi, chiamaprintAll()e poi elimina correttamente il MessageBox per liberare la memoria.
Il formato dell'input sarà:
- Prima riga: la capacità (intero)
- Seconda riga: il numero di messaggi da aggiungere (intero)
- Righe successive: un messaggio per riga
Ricorda: ogni new richiede un delete corrispondente, e ogni new[] richiede un delete[] corrispondente. Dopo aver eliminato un puntatore, è buona norma impostarlo a nullptr.
Includi il file header in main.cpp usando #include "MessageBox.h".
Provalo tu
#include <iostream>
#include <string>
#include "MessageBox.h"
using namespace std;
int main() {
int capacity;
int numMessages;
// Leggi la capacità e il numero di messaggi
cin >> capacity;
cin >> numMessages;
cin.ignore(); // Elimina il carattere di nuova riga dopo il numero
// TODO: Crea un MessageBox nello heap usando new
// TODO: Leggi e aggiungi tutti i messaggi al MessageBox
for (int i = 0; i < numMessages; i++) {
string message;
getline(cin, message);
// Aggiungi il messaggio al MessageBox
}
// TODO: Chiama printAll() per visualizzare tutti i messaggi
// TODO: Elimina il MessageBox per liberare la memoria
// Ricorda di impostare il puntatore a nullptr dopo l'eliminazione
return 0;
}
Questa lezione include un breve quiz. Inizia la lezione per rispondere e tenere traccia dei tuoi progressi.
Tutte le lezioni di Programmazione orientata agli oggetti
1Fondamenti della programmazione orientata agli oggetti
File esterniBuild e compilazione in C++File header e file sorgenteNamespace e ambitoIntroduzione alla programmazione orientata agli oggetti in C++Classi e oggetti a confrontoIl puntatore 'this'Metodi (funzioni membro)Attributi (membri dati)Fondamenti di costruttori e distruttoriRiepilogo - Calcolatrice semplice4Proprietà delle classi
Membri di istanza e staticiGetter e setterFunzioni membro constParola chiave mutableMetodi e variabili staticiFunzioni e classi friendRiepilogo - Gestore di conti bancari7Ereditarietà
Ereditarietà di baseLivelli di accesso nell’ereditarietàOrdine di chiamata di costruttori e distruttoriRidefinizione dei metodiFunzioni virtuali e VTableEreditarietà multiplaEreditarietà virtualeRiepilogo - Gerarchia dei dipendenti2Gestione della memoria
Memoria Stack vs HeapPuntatori e riferimentiMemoria dinamica (new/delete)Puntatori intelligenti in C++RAII in C++Riepilogo - Gestore di array dinamico5Incapsulamento
Specificatori di accesso in C++Specificatori di accesso in dettaglioOccultamento delle informazioniStruct vs classClassi annidate e interneRiepilogo - Sistema di registrazione degli studenti8Polimorfismo
Polimorfismo a compile time e a runtimeOverload delle funzioniFunzioni virtuali: ripassoFunzioni virtuali pureClassi astratteProgettazione delle interfacce in C++Dynamic casting e RTTIRipasso: calcolatrice di forme11Concetti avanzati di OOP
Composizione vs ereditarietàMixin tramite CRTPIdiom PimplType ErasureEnum class e tipizzazione forteGestione delle eccezioni in OOPGerarchie personalizzate di eccezioni14Pattern di progettazione - Parte 2
Pattern CommandPattern AdapterPattern DecoratorPattern Template MethodPattern StatePattern CompositeRAII come pattern3Costruttori e distruttori
Costruttore predefinitoCostruttore con parametriCostruttore di copiaCostruttore di spostamentoListe di inizializzazione dei costruttoriCostruttori delegantiApprofondimento sui distruttoriRegola del Tre / Cinque / ZeroRipasso - classe String6Sovraccarico degli operatori
Introduzione al sovraccarico degli operatoriSovraccarico degli operatori aritmeticiSovraccarico degli operatori di confrontoOperatori di flussoSovraccarico dell'operatore di assegnazioneSovraccarico degli operatori [] e ()Operatori di conversione di tipoRipasso - Classe Matrix9Template
Template di funzioneTemplate di classeSpecializzazione dei templateTemplate variadiciBasi di SFINAE e dei trait di tipoRiepilogo - Contenitore genericoEsercitati da solo: Compilatore C++ online