const adalah janji ke compiler: nilai atau objek ini tidak akan diubah. Janji ini bukan sekadar dokumentasi — kompiler menolak kode yang melanggarnya, sehingga bug mutasi tak sengaja tertangkap saat kompilasi. Lebih dari itu, const memberi sinyal optimisasi: compiler tahu bahwa data tidak berubah, dapat meng-cache nilai di register, atau menghapus pemanggilan fungsi berulang. Pada Chapter ini kita akan memetakan empat tempat const dipakai (variabel, parameter, return, method), perbedaan const T* vs T* const, serta manfaat praktis: keselamatan dan performa.
Empat Tempat const Dipakai #
| Lokasi | Sintaks | Arti |
|---|---|---|
| Variabel lokal | const int k = 100; | k tidak bisa di-assign ulang |
| Parameter | void f(const T& x) | x tidak bisa diubah dalam fungsi |
| Return value | const T& get() const | Pemanggil tidak bisa mutasi hasil |
| Method | int get() const | Method tidak mutasi *this |
Mekanisme: Const sebagai Bagian dari Tipe #
const adalah bagian dari tipe — const int dan int adalah tipe berbeda. Compiler menolak mengkonversi T* ke const T* secara diam-diam? Sebaliknya — konversi T* → const T* aman (menambahkan restriksi), tetapi sebaliknya butuh const_cast (menghapus restriksi — berbahaya bila objek asli benar-benar const).
Untuk method, const setelah parameter (mis. int size() const) menandai method tidak memodifikasi *this. Hanya method const yang bisa dipanggil pada objek const. Method non-const tidak dapat dipanggil — kompiler menolak dengan error “discards qualifiers”.
Kode: Empat Aspek const #
#include <iostream>
#include <vector>
#include <string>
// 1) const parameter — read-only reference
void print_pair(const std::pair<int, std::string>& p) {
// p.first = 99; // ERROR: p adalah const reference
std::cout << "(" << p.first << ", \"" << p.second << "\")\n";
}
// 2) const return value
const std::string& get_name(const std::vector<std::string>& v, size_t i) {
return v.at(i); // return const ref; pemanggil tidak bisa mutasi
}
class Counter {
int n_ = 0;
public:
void inc() { ++n_; }
int get() const { return n_; } // const method — tidak mutasi state
int& ref() { return n_; } // non-const method — bisa mutasi
};
// 3) const_iterator
void print_first_three(const std::vector<int>& v) {
// v.push_back(0); // ERROR: v adalah const reference
auto it = v.cbegin(); // const_iterator — elemen read-only
for (int i = 0; i < 3 && it != v.cend(); ++i, ++it) {
std::cout << *it << ' ';
}
std::cout << '\n';
}
int main() {
std::pair<int, std::string> p{42, "answer"};
print_pair(p);
std::vector<std::string> names = {"alice", "bob", "carol"};
const std::string& nm = get_name(names, 1);
std::cout << "name[1] = " << nm << '\n';
// nm[0] = 'X'; // ERROR: nm adalah const reference
Counter c;
c.inc();
c.inc();
std::cout << "counter.get() = " << c.get() << '\n';
// Bila objek const, hanya method const yang bisa dipanggil
const Counter& cc = c;
std::cout << "cc.get() = " << cc.get() << '\n';
// cc.inc(); // ERROR: cc const, inc() non-const
// cc.ref() = 99; // ERROR: ref() non-const
// const_iterator
std::vector<int> v = {10, 20, 30, 40, 50};
print_first_three(v);
// 4) const local variable
const int k = 100;
// k = 200; // ERROR: k const
std::cout << "k = " << k << '\n';
// 5) const pointer vs pointer to const
int a = 5, b = 7;
const int* ptr_to_const = &a; // pointer ke const int
// *ptr_to_const = 99; // ERROR: tidak bisa mutasi *ptr
ptr_to_const = &b; // OK: bisa re-point
int* const const_ptr = &a; // const pointer ke int
*const_ptr = 99; // OK: bisa mutasi *const_ptr
// const_ptr = &b; // ERROR: pointer sendiri const
std::cout << "a=" << a << ", b=" << b << ", *ptr_to_const=" << *ptr_to_const
<< ", *const_ptr=" << *const_ptr << '\n';
return 0;
}Output yang Dihasilkan:
(42, "answer")
name[1] = bob
counter.get() = 2
cc.get() = 2
10 20 30
k = 100
a=99, b=7, *ptr_to_const=7, *const_ptr=99Bedah Kode Baris-per-Baris #
void print_pair(const std::pair<int, std::string>& p): parameterconst &— fungsi menerima referensi tanpa copy dan berjanji tidak memutasip. Bila di dalam tubuh fungsi terdapatp.first = 99, kompiler menolak. Inilah kontrak yang dimanfaatkan pemanggil.const std::string& get_name(const std::vector<std::string>& v, size_t i): parameter dan return keduanyaconst &. Pemanggilconst std::string& nm = get_name(...)mendapat referensi ke elemennames[1]tanpa copy; mencobanm[0] = 'X'ditolak kompiler.int get() const { return n_; }: methodconst— berjanji tidak memutasi*this. Wajib bila ingin dipanggil pada objekconst(mis.const Counter& cc).int& ref() { return n_; }: method non-const karena mengembalikan referensi non-const ke member. Memanggilcc.ref()ditolak kompiler karenaccconst.const Counter& cc = c;: alias const ke objekc. Hanya method const (get()) yang bisa dipanggil.inc()danref()ditolak.v.cbegin(): mengembalikanconst_iterator— elemen di posisi tersebut bersifatconst int. Sangat berguna bila fungsi menerimaconst std::vector<T>&dan ingin iterasi tanpa risiko mutasi.const int k = 100;: variabel lokal const. Kompiler menolakk = 200. Berguna untuk konstanta yang diberi nama (lebih ekspresif daripada magic number, lebih aman daripada#define).const int* ptr_to_const: pointer keconst int—*ptrtidak bisa dimutasi, tetapiptrsendiri bisa di-assign ulang ke alamat lain. Baca kiri-ke-kanan: “pointer to const int”.int* const const_ptr: const pointer keint—ptrtidak bisa di-assign ulang, tetapi*ptrbisa dimutasi. Baca: “const pointer to int”.- Output
a=99:*const_ptr = 99berhasil —adiubah.b=7karenaptr_to_constdi-assign ulang ke&b, tetapi tidak mengubahb.*ptr_to_const=7(membacab) dan*const_ptr=99(membacaa).
Manfaat Praktis #
1. Bug Detection Lebih Awal #
const menangkap mutasi tak sengaja saat kompilasi:
void process(const std::vector<int>& data) {
data.push_back(0); // ERROR — caught at compile time
}2. Sinyal Optimisasi #
Compiler tahu objek const tidak akan berubah → bisa meng-cache nilai:
size_t total_size(const std::vector<std::string>& v) {
size_t s = 0;
for (const auto& str : v) s += str.size();
return s;
}Karena v const, compiler tahu tidak ada alias yang bisa memodifikasi v selama loop → bisa mengoptimalkan pemanggilan .size().
3. Kontrak API #
Parameter const T& adalah kontrak: “saya hanya membaca, tidak akan mengubah data Anda”. Pemanggil aman melewatkan objek berharga tanpa khawatir disabotase.
4. Compatibility dengan Container Const #
Container const hanya menyediakan const_iterator via begin()/end(). Bila Anda memakai auto it = v.begin() pada const vector, it otomatis const_iterator. Untuk eksplisit: cbegin()/cend().
Jebakan: const_cast #
const_cast<T&>(x) menghapus const. Ini legal hanya bila objek asli benar-benar non-const. Bila objek asli const (mis. const int k = 100 lalu const_cast<int&>(k) = 99), hasilnya undefined behavior. Hindari const_cast kecuali berurusan dengan API C lama.
Ringkasan #
constadalah bagian dari tipe — kompiler menolak mutasi objek const.- Empat lokasi: variabel lokal, parameter, return value, method.
- Method
consthanya bisa dipanggil pada objekconst; method non-const ditolak. const T*(pointer to const) berbeda dariT* const(const pointer) — baca dari kanan ke kiri.constmemungkinkan optimisasi (cache nilai, eliminate call) dan menangkap bug mutasi saat kompilasi.- Hindari
const_castkecuali untuk API C; hapusconstpada objek yang benar-benar const adalah UB. - Aturan praktis: tulis
constdi mana pun bisa, hapus hanya bila terbukti perlu.