Setiap variabel yang kita buat menempati memori. C++ memberi kita kontrol langsung atas di mana dan kapan memori dialokasikan, sekaligus kapan dibebaskan. Kontrol ini adalah kekuatan sekaligus sumber bug paling mahal: kebocoran memori, double free, dan dangling pointer. Pada Chapter ini kita akan mempelajari perbedaan stack dan heap, alokasi manual dengan new/delete, serta pola modern RAII dengan smart pointer yang membebaskan memori secara otomatis.
Stack vs Heap #
C++ mengelola dua region memori utama untuk variabel:
| Region | Karakteristik | Cocok untuk |
|---|---|---|
| Stack | Cepat, otomatis, ukuran terbatas (~1–8 MB) | Variabel lokal, tipe kecil, lifetime singkat |
| Heap | Manual, ukuran besar (GB), lebih lambat | Data besar, lifetime tidak terprediksi |
Mekanisme: Alokasi Stack vs Heap #
Saat kita menulis int x = 10;, compiler memesan slot di stack. Saat scope berakhir, slot dilepaskan otomatis tanpa kode tambahan. Sebaliknya, int* p = new int(10); memesan memori di heap dan mengembalikan pointer. Memori heap tidak dibebaskan otomatis — kita harus memanggil delete p; secara eksplisit.
Kode: Stack vs Heap #
#include <iostream>
struct Buff {
int data[100]; // 400 byte
};
int main() {
std::cout << "sizeof(Buff) = " << sizeof(Buff) << '\n';
Buff b; // di stack, dibebaskan otomatis
b.data[0] = 1;
std::cout << "b.data[0] = " << b.data[0] << '\n';
int* heap_int = new int(42); // di heap
std::cout << "heap_int = " << *heap_int << '\n';
delete heap_int; // WAJIB hapus manual
return 0;
}Output yang Dihasilkan:
sizeof(Buff) = 400
b.data[0] = 1
heap_int = 42- Baris
Buff b;:bdialokasikan di stack. Saat fungsimainberakhir, compiler otomatis membebaskan memorinya. - Baris
sizeof(Buff): struct berisi arrayint[100], total 400 byte. Seluruhnya berada di stack. - Baris
int* heap_int = new int(42);:newmemesan memori di heap dan mengembalikan pointer. Memori tetap dialokasikan sampaideletedipanggil. - Baris
delete heap_int;: membebaskan memori heap. Tanpa baris ini, terjadi memory leak.
Alokasi Manual: new dan delete #
Alokasi manual memberi kendali penuh, tetapi menempatkan beban pembebasan pada programmer. Setiap new harus berpasangan dengan delete; setiap new[] dengan delete[]. Lupa atau salah pasangan menyebabkan bug serius.
Kode: Alokasi Manual #
#include <iostream>
void pakai_manual() {
int* p = new int(42);
std::cout << "manual: " << *p << '\n';
delete p; // WAJIB
}
int main() {
pakai_manual();
return 0;
}Output yang Dihasilkan:
manual: 42- Baris
int* p = new int(42);: memesan 4 byte di heap, mengisi42, kembalikan pointer. - Baris
delete p;: membebaskan memori yang ditunjukp. Setelah ini,pmenjadi dangling — mengaksesnya adalah undefined behavior.
RAII: Resource Acquisition Is Initialization #
RAII adalah idiom C++ yang mengikat resource ke lifetime objek. Saat objek dibuat, resource diakuisisi (alokasi, buka file, lock mutex); saat objek dihancurkan, resource dilepas. Dengan RAII, kita tidak perlu memanggil delete manual — destructor objek melakukannya.
Mekanisme: Destructor sebagai Penjaga #
Setiap kelas bisa mendefinisikan destructor ~Nama(). Destructor dipanggil otomatis saat objek keluar scope — bahkan bila terjadi exception. Inilah pondasi keamanan memori modern C++.
Kode: Destructor dan Scope #
#include <iostream>
class Logger {
public:
Logger() { std::cout << "ctor\n"; }
~Logger() { std::cout << "dtor\n"; }
};
int main() {
{
Logger log;
std::cout << "di dalam scope\n";
}
std::cout << "keluar scope\n";
return 0;
}Output yang Dihasilkan:
ctor
di dalam scope
dtor
keluar scope- Baris
Logger log;: constructor dipanggil, mencetakctor. - Baris
}(akhir scope dalam): destructor dipanggil otomatis, mencetakdtor. Ini terjadi bahkan bila ada exception di dalam scope. - Baris
keluar scope: dicetak setelah destructor — menunjukkan urutan yang benar.
Smart Pointer #
C++11 memperkenalkan smart pointer yang mengelola memori heap secara otomatis via RAII. Dua yang paling penting:
| Smart pointer | Kepemilikan | Kapan dipakai |
|---|---|---|
std::unique_ptr<T> | Eksklusif (satu pemilik) | Default untuk heap; paling efisien |
std::shared_ptr<T> | Berbagi (reference counting) | Bila banyak pemilik butuh akses |
Mekanisme: unique_ptr vs shared_ptr #
unique_ptr tidak bisa di-copy — hanya di-move. Saat unique_ptr keluar scope, destructor otomatis memanggil delete. shared_ptr memakai reference count; memori baru dibebaskan saat hitungan mencapai nol.
Kode: Smart Pointer #
#include <iostream>
#include <memory>
#include <vector>
void pakai_unique() {
auto p = std::make_unique<int>(99);
std::cout << "unique: " << *p << '\n';
// tidak perlu delete — dibebaskan otomatis
}
void pakai_vector() {
auto v = std::make_unique<std::vector<int>>(10, 5);
std::cout << "vector size: " << v->size() << '\n';
// dibebaskan otomatis
}
int main() {
pakai_unique();
pakai_vector();
// Shared ownership
auto shared = std::make_shared<int>(7);
auto shared2 = shared;
std::cout << "use_count = " << shared.use_count() << '\n';
*shared2 = 100;
std::cout << "shared = " << *shared << '\n';
return 0;
}Output yang Dihasilkan:
unique: 99
vector size: 10
use_count = 2
shared = 100- Baris
std::make_unique<int>(99): membuatunique_ptr<int>yang mengelolaintdi heap. Memori dibebaskan saatpkeluar scope. - Baris
auto v = std::make_unique<std::vector<int>>(10, 5);:unique_ptrkevectordengan 10 elemen bernilai 5. Pola ini sering dipakai untuk mengelola container besar secara otomatis. - Baris
auto shared2 = shared;:shared_ptrbisa di-copy — kedua pointer sekarang menunjuk objek yang sama. Reference count menjadi2. - Baris
shared.use_count(): mengembalikan jumlah pemilik aktif. Saat kedua pointer keluar scope, count turun ke0dan memori dibebaskan. - Baris
*shared2 = 100;: modifikasi melalui salah satushared_ptrterlihat dari yang lain — keduanya menunjuk memori yang sama.
Memory Leak: Apa dan Mengapa #
Memory leak terjadi bila memori heap dialokasikan tetapi tidak pernah dibebaskan. Program tetap berjalan, tetapi konsumsi memori terus tumbuh. Pada program lama atau server yang berjalan berhari-hari, leak dapat menguras seluruh RAM sistem.
Penyebab Umum Leak #
- Lupa
deletesetelahnew. - Exception terjadi sebelum
deletedipanggil — control flow melompati pembersihan. - Pointer ditimpa dengan nilai baru sebelum
deleteyang lama. - Cycle reference pada
shared_ptryang saling menunjuk.
Solusi Modern #
RAII + smart pointer menyelesaikan masalah 1, 2, dan 3. Untuk masalah 4 (cycle reference), gunakan std::weak_ptr untuk memutus siklus — akan dibahas pada bab Graph.
Ringkasan #
- Stack: cepat, otomatis, terbatas. Heap: manual, besar, lebih lambat.
- Setiap
newwajib berpasangan dengandelete;new[]dengandelete[]. Mencampur pasangan adalah undefined behavior. - RAII mengikat resource ke lifetime objek — destructor otomatis membebaskan saat scope berakhir, bahkan bila terjadi exception.
std::unique_ptradalah default untuk heap modern — efisien dan aman.std::shared_ptruntuk kepemilikan bersama.- Memory leak dihindari dengan RAII dan smart pointer; hindari
new/deletemanual di kode produksi.