Dua Chapter terakhir menyisakan dilema: pass by value aman tetapi mahal untuk data besar, sedangkan pass by reference hemat tetapi membuka pintu perubahan yang tidak selalu kita mau. C++ menawarkan kombinasi keduanya dalam satu kata kunci: pass by const reference, ditulis const T&. Parameter ini tetap alias tanpa salinan seperti T&, tetapi berlabel const sehingga fungsi DILARANG mengubahnya — dan compiler yang menegakkan larangan itu. Pada Chapter ini kita membiasakan pola yang paling sering muncul di kode C++ profesional, lalu merumuskan aturan praktis memilih cara passing.

const&: Hemat dan Aman Sekaligus #

Program berikut menampung ketiga cara passing dalam satu file, masing-masing dipakai sesuai tugasnya:

cpp
#include <iostream>
#include <string>
#include <vector>

// Membaca vector besar: const& — hemat salinan, tetap tidak bisa diubah
double rataRata(const std::vector<int>& data) {
    double total = 0.0;
    for (int nilai : data) {
        total += nilai;
    }
    return total / data.size();
}

// Mengubah vector pemanggil: pakai & tanpa const
void tambahNilai(std::vector<int>& data, int nilai) {
    data.push_back(nilai);
}

// Data kecil fundamental: cukup pass-by-value
int kuadrat(int x) {
    return x * x;
}

int main() {
    std::vector<int> nilaiUjian = {80, 90, 70, 100};
    std::cout << "Rata-rata: " << rataRata(nilaiUjian) << "\n";

    tambahNilai(nilaiUjian, 60);
    std::cout << "Jumlah data sekarang: " << nilaiUjian.size() << "\n";
    std::cout << "Rata-rata baru: " << rataRata(nilaiUjian) << "\n";

    std::cout << "Kuadrat dari 12: " << kuadrat(12) << "\n";
    return 0;
}

Output yang Dihasilkan:

text
Rata-rata: 85
Jumlah data sekarang: 5
Rata-rata baru: 80
Kuadrat dari 12: 144

Mari kita bedah ketiga fungsinya: Baris 7 (rataRata) menerima const std::vector<int>& — std::vector, container array dinamis standar yang kita kenal pada Section Control Flow — sehingga jutaan elemen bisa dibaca tanpa satu salinan pun dibuat, sementara label const menjamin fungsi hanya membaca. Baris 15 (tambahNilai) sengaja memakai std::vector<int>& tanpa const karena tugasnya menambah elemen lewat push_back; inilah kasus yang memang butuh reference biasa. Baris 21 (kuadrat) menerima satu int lewat value, karena salinan empat byte lebih murah daripada dereferensi alias. Tiga fungsi, tiga pilihan, semuanya berdasarkan tugas — bukan kebiasaan.

Compiler Menjaga Janji const #

Janji const bukan sekadar catatan kaki dokumentasi — compiler menegakkannya. Coba tambahkan satu baris pengubahan pada parameter const&; potongan berikut kami jalankan sungguhan untuk menangkap pesan galatnya:

cpp Potongan bermasalah: mengubah parameter const&
void rubah(const int& nilai) {
    nilai = 10;   // DITOLAK: nilai adalah reference const
}

int main() {
    int a = 5;
    rubah(a);
    return 0;
}

Pesan galat g++-nya singkat dan jelas: error: assignment of read-only reference 'nilai'. Perilaku ini adalah nilai jual utama const&: fungsi yang menerima const std::string& bisa kita panggil dengan data berharga mana pun tanpa takut datanya diubah, karena compiler yang menjadi penjaganya — bukan disiplin manual pembaca kode. Bandingkan dengan T& biasa: kehati-hatian bergantung sepenuhnya pada niat yang hanya tertulis di kepala penulis fungsi. Di sinilah letak perbedaan praktis antara “hemat” dan “hemat yang aman”.

Aturan Praktis Memilih Cara Passing #

Ketiga mekanisme kini lengkap, dan pilihannya bisa dirumuskan dalam tabel yang ringkas:

SituasiCara passingAlasan
Fungsi membaca data besar (std::string, std::vector)const T&Tanpa salinan, tanpa risiko perubahan
Fungsi mengubah data pemanggilT&Alias satu-satunya jalan menuju perubahan
Data kecil fundamental (int, double, char, bool)T (value)Salinan lebih murah daripada lewat alias
Fungsi menghasilkan satu nilaireturn valuereturn tetap cara utama mengirim hasil

Aturan di atas mencakup mayoritas kasus sehari-hari. Ada satu detail yang menyenangkan: const& juga menerima nilai sementara — rataRata({90, 80, 70}) sah — karena reference const boleh menempel pada data sementara yang hidup selama pemanggilan; detail aturan hidupnya dibahas pada cppreference: reference initialization , sedangkan halaman cppreference: reference declaration merangkum seluruh bentuk reference.

Dengan tiga cara passing sudah dikuasai, perangkat fungsi kita nyaris lengkap. Tinggal satu penyelesaian kecil yang sering dilupakan: bagaimana bila sebagian argumen hampir selalu bernilai sama? Di sanalah default arguments berperan.