Ketiga loop yang sudah kita pelajari — for, while, do-while — mengandalkan counter dan kondisi indeks. Padahal kebutuhan yang paling sering muncul jauh lebih sederhana: “kerjakan sesuatu untuk SETIAP elemen dalam koleksi ini”. Loop yang disebut range-based for (bentuk lengkapnya for (elemen : koleksi)) dirancang khusus untuk itu; ia diperkenalkan di C++11 dan sejak itu menjadi loop paling populer di kode C++ modern. Pada Chapter ini kita mengunjungi array, std::string, dan std::vector dengannya, lalu membahas keputusan penting di balik bentuknya: menyalin elemen atau meminjamnya lewat reference.
Bentuk Dasar: Setiap Elemen, Tanpa Indeks #
Strukturnya dua bagian: di kiri titik dua ada variabel yang menerima elemen, di kanan ada koleksinya. Loop sendiri yang mengurus pengambilan elemen dari awal sampai akhir — tidak ada i, tidak ada i < ukuran, tidak ada kemungkinan salah batas. Mari kita kunjungi tiga jenis koleksi sekaligus:
#include <iostream>
#include <string>
#include <vector>
int main() {
// std::vector: container dinamis; dibahas tuntas pada Chapter std::vector
std::vector<int> skor = {90, 85, 77};
for (int s : skor) {
std::cout << "Skor: " << s << "\n";
}
for (int x : {2, 4, 6}) { // initializer_list literal
std::cout << "Angka: " << x << "\n";
}
std::string nama = "Budi";
for (char c : nama) { // setiap karakter dalam string
std::cout << c << "\n";
}
return 0;
}Output yang Dihasilkan:
Skor: 90
Skor: 85
Skor: 77
Angka: 2
Angka: 4
Angka: 6
B
u
d
iTiga koleksi, satu pola:
- Baris 7 (
std::vector<int> skor):std::vectoradalah container standar yang isinya bisa bertambah — di Chapter ini cukup dipahami sebagai “daftar nilai”; detailnya menanti pada Chapter std::vector di Section Array dan String. Karena ada di sini, header<vector>ikut di-include pada baris 3. - Baris 9-11 (
for (int s : skor)): pada setiap putaran, elemen berikutnya dariskordisalin ke variabels, lalu badan mencetaknya. Loop berjalan persis sebanyak jumlah elemen — 3 putaran, tanpa konstanta batas yang ditulis tangan. - Baris 13-15 (
for (int x : {2, 4, 6})): kanan titik dua boleh berupa initializer_list literal — daftar nilai yang ditulis langsung di tempat, praktis untuk iterasi sekali jalan. - Baris 18-20 (
for (char c : nama)):std::stringpun bisa dikunjungi; yang “diputarkan” adalah karakternya satu per satu, sehingga tiap huruf “Budi” tercetak pada barisnya sendiri.
Perhatikan apa yang HILANG dari kode ini dibanding loop berindeks: tidak ada deklarasi batas, tidak ada ekspresi skor[i], dan tidak ada peluang kesalahan off-by-one (salah satu/dua putaran). Bila kita menulis for (int s : skor) atas koleksi 3 elemen, jumlah putarannya dijamin 3. Sintaks lengkap range-based for tersaji di cppreference
.
by Value versus by Reference #
Kiri titik dua adalah deklarasi variabel biasa — dan di sanalah keputusan penting bersembunyi: int s menerima SALINAN elemen, sedangkan int& s menerima alias ke elemen aslinya. Tanda & di situ menandai reference, konsep yang akan dibedah tuntas pada Section Pointer dan Reference; untuk sekarang cukup pahami bahwa & mengubah “salinan” menjadi “jendela ke aslinya”. Program berikut memperlihatkan konsekuensinya:
#include <iostream>
#include <vector>
int main() {
std::vector<int> harga = {10, 20, 30};
// by value: mengubah salinan, elemen asli tidak tersentuh
for (int h : harga) {
h = h * 2;
}
std::cout << "Setelah loop by value: "
<< harga[0] << ", " << harga[1] << ", " << harga[2] << "\n";
// by reference: mengubah elemen asli di dalam vector
for (int& h : harga) {
h = h * 2;
}
std::cout << "Setelah loop by reference: "
<< harga[0] << ", " << harga[1] << ", " << harga[2] << "\n";
// const reference: membaca tanpa menyalin, gaya modern dengan auto
for (const auto& h : harga) {
std::cout << "Harga: " << h << "\n";
}
return 0;
}Output yang Dihasilkan:
Setelah loop by value: 10, 20, 30
Setelah loop by reference: 20, 40, 60
Harga: 20
Harga: 40
Harga: 60Tiga loop, tiga pelajaran:
- Loop pertama (
for (int h : harga)):hadalah salinan; menggandakannya dua kali hanya mengubah salinan yang dibuang di akhir putaran. Vector tetap 10, 20, 30 — inilah sumber bug klasik pemula: “loop saya berjalan, tetapi datanya tidak berubah”. - Loop kedua (
for (int& h : harga)): tanda&membuathalias ke elemen asli; perkalian menulis ulang elemen vector itu sendiri, sehingga tercetak 20, 40, 60. - Loop ketiga (
for (const auto& h : harga)):constmelarang perubahan sekaligus mendokumentasikan niat “hanya baca”, sedangkanautomembiarkan compiler menyimpulkan tipenya (lihat Chapter auto dan Type Deduction). Bentukconst auto&inilah gaya bawaan yang dianjurkan untuk membaca koleksi: benar, aman, dan tanpa biaya penyalinan.
Koleksi Apa Saja yang Didukung #
Range-based for bekerja pada semua koleksi yang punya awal dan akhir — konsep yang disebut range dan dibedah lebih dalam pada Section Iterators dan Algorithms. Yang sudah Anda pegang saat ini:
- Array C biasa seperti
int data[] = {1, 2, 3};— loop tahu panjangnya dari tipenya. std::string— memutarkan karakter, seperti contoh pertama.std::vectordanstd::array— container standar;std::arraydibahas pada Chapter std::array dan std::vector di Section Standard Library.initializer_listliteral seperti{2, 4, 6}— daftar sementara yang ditulis langsung.
Satu detail mekanisme yang menenangkan: bila kanan titik dua berupa objek sementara (temporary), misalnya for (char c : std::string{"halo"}), C++ memperpanjang masa hidup objek sementara itu sampai loop selesai — sehingga pola di aman dan tidak membaca objek yang sudah dibongkar. Meski demikian, bentuk yang paling umum di kode nyata tetap mengiterasi variabel yang berumur lebih panjang.
Dengan range-based for, mengunjungi koleksi kini semurah satu baris header. Namun loop yang panjang sering perlu dihentikan di tengah jalan atau melompati putaran tertentu — dua kebutuhan yang dilayani break dan continue, topik Chapter berikutnya.