Satu objek di heap jarang cukup — kebutuhan nyata sering berupa serangkaian elemen yang jumlahnya baru diketahui saat program berjalan, misalnya array sepanjang jumlah baris data yang dibaca pengguna. Untuk itu C++ menyediakan bentuk array dari alokasi dinamis: new T[n] memesan memori untuk n elemen berurutan, dan delete[] melepaskannya kembali. Pasangan ini datang dengan aturan yang paling sering tertukar oleh pemula: kurung siku pada delete[] bukan opsi, melainkan kewajiban yang harus cocok dengan new[] yang memulainya. Chapter ini menguji pasangan tersebut, membedah mengapa tukar-menukar bentuknya berujung pada undefined behavior, lalu menutup dengan dua alternatif modern yang membuat kita praktis tidak perlu menulisnya lagi.
Alokasi Array dengan new[] #
Bentuk new double[n] mengalokasikan n elemen bertipe double yang saling berurutan di heap dan mengembalikan pointer ke elemen pertama. Berbeda dengan array C-style yang ukurannya harus konstan, n di sini boleh berupa nilai yang baru diketahui saat runtime — dari input, dari perhitungan, atau dari ukuran berkas. Akses elemennya memakai notasi nilai[i] yang sudah kita kenal dari Chapter Pointer dan Array.
#include <iostream>
int main() {
int n = 5; // ukuran boleh ditentukan saat runtime
double* nilai = new double[n]; // alokasi array di heap
for (int i = 0; i < n; ++i) {
nilai[i] = (i + 1) * 2.5;
}
double total = 0.0;
for (int i = 0; i < n; ++i) {
total += nilai[i];
}
std::cout << "Rata-rata: " << total / n << "\n";
delete[] nilai; // kurung siku WAJIB karena alokasinya memakai new[]
nilai = nullptr;
return 0;
}Output yang Dihasilkan:
Rata-rata: 7.5Yang terjadi di balik program singkat di atas:
- Baris 5 (
new double[n]): alokator memesan5 × sizeof(double)byte sekaligus; tidak ada constructor per elemen untuk tipe fundamental, isinya tidak dijamin terisi. - Baris 7-9 (loop pengisian):
nilai[i]setara dengan*(nilai + i)— pointer aritmetika yang kita pelajari pada Section Pointer dan Reference bekerja di atas blok heap ini. - Baris 11-15 (loop penjumlahan): data diakses seperti array biasa; yang berbeda hanyalah lokasinya, yaitu heap, dan umurnya yang melampaui blok.
- Baris 17 (
delete[] nilai;): seluruh blok dikembalikan sekaligus. Tanpa baris ini, 40 byte bocor setiap kali fungsi semacam ini dijalankan.
delete[] Wajib Cocok dengan new[] #
Aturan kuncinya satu: alokasi new[] hanya boleh dilepas dengan delete[]. Mencabut kurung sikunya adalah undefined behavior:
double* data = new double[100];
delete data; // UNDEFINED BEHAVIOR: harusnya delete[]
Mengapa bendanya begitu tegas? Karena new[] mencatat jumlah elemen di pembukuan alokator — itulah cara delete[] tahu berapa banyak elemen yang harus dikonstruksi balik dan dilepas. delete tanpa kurung siku dirancang untuk satu objek: ia melewatkan pencatatan itu, sehingga pelepasannya tidak cocok dengan pola alokasinya. Pada tipe class dengan destructor, akibatnya lebih terlihat: destructor elemen kedua sampai terakhir tidak pernah dijalankan, sementara heap menerima permintaan pelepasan yang tidak sesuai pembukuan. g++ dengan -fsanitize=address biasanya menyebut kesalahan ini sebagai alloc-dealloc-mismatch.
Alternatif Modern: unique_ptr<T[]> dan vector #
Kepemilikan array heap dapat diserahkan ke smart pointer std::unique_ptr<T[]>, yang khusus memakai delete[] sebagai pelepasnya. Dengan begitu aturan kurung siku didelegasikan ke library, dan kita tinggal memakai objeknya:
#include <iostream>
#include <memory>
int main() {
int n = 5;
std::unique_ptr<double[]> nilai = std::make_unique<double[]>(n);
for (int i = 0; i < n; ++i) {
nilai[i] = (i + 1) * 2.5;
}
double total = 0.0;
for (int i = 0; i < n; ++i) {
total += nilai[i];
}
std::cout << "Rata-rata: " << total / n << "\n";
// Tidak ada delete[]: array dibebaskan otomatis saat nilai selesai.
return 0;
}Output yang Dihasilkan:
Rata-rata: 7.5Program kedua ini menghasilkan output yang persis sama, tetapi tanpa satu baris pelepasan manual. std::make_unique<double[]>(n) menciptakan array heap yang dimiliki nilai, dan destructor unique_ptr menjalankan delete[] yang tepat saat nilai berakhir — mekanismenya menyusul pada Chapter unique_ptr. Pilihan ketiga sebenarnya paling sering dipakai: std::vector<double> dari Section Array dan String yang sudah kita kuasai, yang mengelola alokasi, ukuran, dan pelepasan sekaligus.
Rangkaian pasangan alokasi-pelepasan yang kita pegang kini sudah lengkap: new/delete dan new[]/delete[]. Pertanyaannya, apa yang terjadi bila salah satu sisi pasangan itu terlupa? Chapter berikutnya mengkhususkan diri pada kebocoran memori — penyakit senyap yang lahir dari kelalaian itu.
Referensi: cppreference — new expression , cppreference — delete expression , cppreference — std::unique_ptr .