Pertanyaan “kenapa C++, bukan C atau Rust?” hampir pasti muncul saat kita mulai belajar bahasa ini. Ketiganya sama-sama compiled, statically typed, tanpa garbage collector, dan menargetkan performa tinggi — itulah yang membuat perbandingannya menarik, sekaligus tidak bisa dijawab dengan satu kalimat. Pada Chapter ini kita membandingkan C++, C, dan Rust secara teknis dan netral: level abstraksi, manajemen memori, kompatibilitas, ekosistem, serta kurva belajarnya. Di bagian akhir, kita membuktikan pembeda terbesarnya — RAII — lewat program kecil yang benar-benar kita jalankan.
Tiga Bahasa, Tiga Latar Belakang #
C diciptakan Dennis Ritchie di Bell Labs sekitar 1972 sebagai bahasa untuk menulis sistem UNIX. C++ tumbuh dari C pada 1985 lewat penambahan fitur abstraksi oleh Bjarne Stroustrup — juga di Bell Labs. Rust paling muda: dimulai sebagai proyek riset di Mozilla, versi 1.0 dirilis pada 2015. Ketiganya mengompilasi source code menjadi machine code native dan tidak memakai garbage collector, tetapi filosofi manajemen memorinya berbeda — dan perbedaan inilah pembeda terbesarnya.
| Aspek | C | C++ | Rust |
|---|---|---|---|
| Tahun rilis | 1972 | 1985 | 2015 (versi 1.0) |
| Paradigma | Prosedural | Multi-paradigm: prosedural, object-oriented, generic, functional | Multi-paradigm berbasis ownership |
| Manajemen memori | Manual (malloc/free) | Manual + RAII + smart pointer | Ownership + borrow checker |
| Jaminan safety | Bergantung disiplin programmer | Bergantung disiplin plus alat bantu (sanitizer, static analysis) | Diperiksa compiler untuk kode safe Rust |
| Learning curve | Permukaan kecil, detail level rendah berat | Luas; butuh waktu untuk seluruh fitur | Aturan ketat sejak awal; borrow checker menantang pemula |
| Basis kode luas | Kernel, RTOS, embedded | Game engine, browser, database, HFT | Tool sistem, WebAssembly, komponen kernel baru |
Manajemen Memori: Pembeda Terbesar #
Dalam C, programmer meminta memori lewat malloc dan mengembalikannya lewat free secara manual. Kontrol penuh memberi prediktabilitas tinggi dan runtime yang minimal — dua hal yang menjadikan C andalan di kernel dan microcontroller. Imbalannya, kelalaian sekecil apa pun — free terlambat, free dua kali, atau tidak pernah free — menghasilkan memory leak atau undefined behavior.
C++ mewarisi kontrol yang sama, lalu menambahkan otomasi berbasis objek yang disebut RAII (Resource Acquisition Is Initialization): akuisisi resource dilakukan saat objek dibuat, dan pelepasannya dijalankan otomatis ketika objek berakhir melalui destructor. Smart pointer kemudian membawa pola ini ke memori heap (dibahas pada Chapter unique_ptr). Hasilnya, kode C++ bisa jauh lebih aman daripada C tanpa menyerahkan apa pun ke garbage collector, dan programmer tetap bebas turun ke level malloc/free bila memang diperlukan.
Rust mengambil jalan lain: ownership. Setiap nilai memiliki satu pemilik, dan aturan pinjaman (borrowing) diperiksa oleh borrow checker pada saat kompilasi. Bila aturan dilanggar, compiler menolak program sebelum ia sempat berjalan, sehingga kelas bug seperti use-after-free dan data race hilang pada kode safe Rust. Konsekuensinya, programmer baru sering menghabiskan bulan-bulan pertama berdiskusi dengan compiler sebelum polanya terbentuk.
Kompatibilitas dan Interoperabilitas #
C adalah bahasa penghubung industri: ABI (Application Binary Interface)-nya stabil dan hampir semua bahasa menyediakan FFI (Foreign Function Interface) ke C. Kernel Linux, banyak RTOS, dan pustaka sistem operasi ditulis dalam C, sehingga C praktis ada di mana-mana. Kode C juga paling mudah dipanggil dari bahasa lain; Python, Rust, dan Go semuanya memiliki jembatan ke C.
C++ dirancang agar sebagian besar kode C tetap bisa dikompilasi ulang sebagai C++ — kompatibilitas sumber, meskipun bukan superset mutlak karena ada perbedaan semantik kecil. Ekosistem C++ yang raksasa (game engine, framework grafis, database) menjadi alasan kuat proyek memilihnya. Rust lebih muda; interoperabilitas resminya berjalan lewat FFI C. Memanggil C dari Rust relatif mudah, sedangkan memanggil C++ dari Rust lebih rumit karena ABI C++ tidak pernah distandarisasi dan name mangling berbeda antar compiler.
Learning Curve dan Pengalaman Pengembangan #
C tampak kecil di permukaan — kata kunci dan fiturnya sedikit — tetapi menguasainya berarti menaklukkan pointer, memori, dan undefined behavior secara manual. Kebanyakan kesalahan C baru muncul saat runtime, kadang jauh dari baris penyebabnya, sehingga debugger menjadi alat wajib. Kecocokan antara mental model programmer dan realitas mesin adalah kekuatan sekaligus tantangan C.
Kurva belajar C++ panjang karena permukaan fiturnya luas: template, overload resolution, model memori, dan konstelasi pustaka standar. Kabar baiknya, subset modern — RAII, STL, sedikit lambda — sudah produktif dalam beberapa bulan, dan alat bantu seperti sanitizer serta -Wall -Wextra menangkap banyak bug lebih awal. Rust justru menegakkan disiplin sejak hari pertama; error borrow checker terasa mahal di awal, tetapi murah setelah pola pikirnya terbentuk, dan tooling Cargo plus crates.io sering dipuji sebagai yang paling seragam di antara ketiganya.
Kapan Memilih yang Mana #
Kerangka keputusan berikut membantu kita menjawab pertanyaan ini secara berimbang:
- Pilih C bila targetnya microcontroller dengan runtime minimal, kita menulis atau merawat kode kernel dan pustaka sistem, portabilitas maksimum lintas platform menjadi syarat, atau basis kode C yang ada lebih menentukan daripada fitur bahasa baru.
- Pilih C++ bila proyek menuntut performa tinggi sekaligus abstraksi kaya — game engine, grafis, simulasi, HFT, database — atau kita perlu mengintegrasikan ekosistem C++ yang besar dan merawat basis kode C++ yang sudah ada.
- Pilih Rust bila memory safety menjadi syarat utama proyek sistem yang baru dimulai, kita membangun tool CLI, aplikasi WebAssembly, atau komponen paralel yang rawan data race, dan tim siap menerima disiplin compiler.
Dalam praktiknya, ketiganya hidup berdampingan. Browser Firefox menggabungkan C++ dan Rust; kernel Linux yang berbasis C kini menerima driver Rust; banyak proyek C++ menautkan pustaka C di bawahnya. Menguasai salah satunya membuat mempelajari dua lainnya jauh lebih cepat karena fondasi mentalnya beririsan.
RAII dalam Kode: Inti Argumentasi C++ #
Untuk merasakan pembeda terbesar tadi secara nyata, perhatikan program kecil berikut. Konsep class belum kita bahas tuntas — materi lengkapnya ada di Section Pemrograman Berorientasi Objek — untuk sekarang cukup pahami class sebagai cetakan objek yang punya dua fungsi istimewa: constructor yang berjalan saat objek dibuat, dan destructor yang berjalan otomatis saat objek berakhir.
#include <iostream>
#include <string>
// Class sederhana yang mengelola satu "sumber daya" (disimulasikan).
class Koneksi {
public:
explicit Koneksi(std::string nama) : nama_(nama) {
std::cout << "Membuka koneksi: " << nama_ << "\n";
}
~Koneksi() {
std::cout << "Menutup koneksi: " << nama_ << "\n";
}
private:
std::string nama_;
};
void prosesPermintaan() {
Koneksi db("database-utama");
std::cout << "Memproses permintaan...\n";
// Tidak ada perintah "tutup" di sini: destructor yang menutup otomatis.
}
int main() {
prosesPermintaan();
std::cout << "Program selesai.\n";
return 0;
}Output yang Dihasilkan:
Membuka koneksi: database-utama
Memproses permintaan...
Menutup koneksi: database-utama
Program selesai.Mari kita bedah mekanisme yang membuat urutan output di atas terjadi:
- Baris 6-8 (constructor
Koneksi): berjalan tepat saat objek dibuat; program mencetakMembuka koneksidi baris pertama output. - Baris 9-11 (destructor
~Koneksi): tanda~menandai destructor — fungsi yang dipanggil compiler secara otomatis ketika objek berakhir, tanpa kita memanggilnya. - Baris 18 (
Koneksi db(...)): objekdblahir di dalam fungsiprosesPermintaan(), sehingga constructor berjalan. - Baris 19: pekerjaan seolah “dilakukan” di antara pembukaan dan penutupan; perhatikan tidak ada perintah menutup koneksi di fungsi ini.
- Baris 21:
prosesPermintaan()berakhir, objekdbkeluar dari scope, dan destructor berjalan otomatis — itulah sebabnyaMenutup koneksitercetak sebelum baris terakhirmain().
Pola inilah yang membedakan disiplin ketiga bahasa. Pada C, kita wajib mengingat pemanggilan penutup resource secara manual di setiap jalur keluar fungsi, termasuk jalur error — kelalaian satu jalur berarti kebocoran. Pada Rust, pola serupa dicapai lewat trait Drop yang juga dipanggil otomatis, mirip destructor C++. Pola RAII menjadi fondasi hampir semua idiom C++ modern dan dibahas mendalam pada Chapter RAII di Section Manajemen Memori; referensi ringkasnya ada di halaman RAII cppreference
dan C++ FAQ isocpp.org
.
Dengan kerangka perbandingan ini, kita siap melihat bukti di lapangan: domain-domain nyata yang memilih C++ dan alasan teknisnya. Chapter berikutnya memetakan penggunaan C++ mulai dari game engine, browser, database, hingga infrastruktur machine learning.