Memori heap hanyalah salah satu dari banyak resource yang harus dikelola sebuah program C++. Resource adalah segala sesuatu yang dibawa masuk, dipakai, lalu harus dikembalikan: file handle yang dibuka dan ditutup, mutex yang dikunci dan dibuka kembali, socket jaringan yang dibuat dan ditutup, serta memori yang dialokasikan dan dibebaskan. Semua kategori itu berbagi pola hidup yang sama — acquire, use, release — dan berbagi risiko yang sama: bila release terlupa di satu jalur eksekusi, resource itu tersangkut sampai program berakhir. Chapter ini menyatukan semua kategori di bawah satu pola, membuktikan kontras antara resource yang dilepas otomatis dan manual, lalu menetapkan prinsip kepemilikan yang menjadi fondasi RAII pada chapter berikutnya.
Pola Acquire-Use-Release #
Setiap pemakaian resource mengikuti tiga tahap yang sama. Acquire meminta resource dari penyedia — new dari alokator, open() dari sistem berkas, lock() dari mutex. Use memakai resource selama masih sah. Release mengembalikannya sehingga pemakai lain bisa mendapatkannya. Pola versi manualnya tampak ringan:
void simpanCatatan() {
std::ofstream berkas("catatan.txt"); // acquire
// ... use: tulis data ...
berkas.close(); // release
}Masalah pola ini bukan pada barisnya, melainkan pada asumsinya: bahwa setiap jalur eksekusi pasti melewati baris release. Satu return di tengah use, satu throw saat menulis, satu kondisi keluar lebih awal — dan resource itu tersangkut. Untuk memori heap, akibatnya adalah memory leak dari chapter sebelumnya; untuk file handle, berkas menempel sampai program berakhir; untuk mutex, program lain menunggu selamanya. Semakin banyak jalur keluar yang sah, semakin banyak titik release yang harus kita tulis dan kita ingat.
Dua Resource Berdampingan dalam Satu Program #
Program berikut memakai dua kategori resource secara bersamaan: file handle lewat std::ofstream dan std::ifstream (kelas pustaka standar untuk membaca dan menulis berkas, dibahas penuh pada Section Input-Output dan File), serta memori heap lewat new[]. Perhatikan kontras perlakuannya: yang satu dilepas otomatis, yang lain menuntut baris pelepasan dari kita.
#include <fstream>
#include <iostream>
#include <string>
int main() {
// Resource 1: file handle — std::ofstream menutupnya otomatis
{
std::ofstream keluar("catatan.txt");
keluar << "Pola acquire-use-release pada berkas\n";
} // close() dipanggil destructor std::ofstream di sini
std::ifstream masukan("catatan.txt");
std::string baris;
std::getline(masukan, baris);
std::cout << "berkas : " << baris << "\n";
// Resource 2: memori heap — harus dilepas secara manual
int* data = new int[3]{10, 20, 30};
int total = 0;
for (int i = 0; i < 3; ++i) {
total += data[i];
}
std::cout << "memori : total " << total << "\n";
delete[] data; // kita sendiri yang bertanggung jawab melepas
data = nullptr;
return 0;
}Output yang Dihasilkan:
berkas : Pola acquire-use-release pada berkas
memori : total 60Bedah penting dari kedua sisi kontras itu:
- Baris 7-10 (blok
std::ofstream): acquire terjadi saat constructor membuka berkas; destructor memanggilclose()tepat saat blok berakhir. Tidak ada satu baris pelepasan pun yang kita tulis — pustaka standar sudah menerapkan RAII untuk kita. - Baris 12-15 (
std::ifstream+getline): membaca balik isi berkas membuktikan bahwa berkas benar-benar sudah ditulis dan ditutup sebelum dibaca. - Baris 18 (
new int[3]{10, 20, 30}): memori heap di-acquire manual; umurnya kini melekat pada pointerdata, bukan pada blok. - Baris 24 (
delete[] data;): release manual yang wajib kita tulis sendiri. Lupa baris ini berarti kebocoran — dan pola ini yang akan kita hilangkan pada dua chapter berikutnya.
Prinsip: Siapa Mengalokasikan yang Melepas #
Dari semua aturan kepemilikan, satu prinsip menjadi pagar utama: pemanggil yang meng-acquire resource adalah pemanggil yang bertanggung jawab melepaskannya, pada fungsi yang sama kecuali ada alasan eksplisit untuk tidak. Ketika fungsi buat() mengembalikan memori yang dialokasikannya, kontrak itu harus tertulis jelas — siapa melepas, kapan, dengan operator apa. Ambiguitas kepemilikan adalah biang dari leak dan double delete: dua pihak saling menunggu yang lain melepas, atau keduanya melepas.
Prinsip “siapa mengalokasikan yang melepas” menuntut pelepasan otomatis agar tidak bergantung pada ingatan programmer. Mekanisme yang membuat pelepasan otomatis itu mungkin sudah kita miliki sejak Section Pemrograman Berorientasi Objek: destructor. Chapter berikutnya menggabungkan keduanya menjadi idiom RAII.
Referensi: cppreference — RAII , cppreference — std::basic_ofstream .