Banyak data di dunia nyata berbentuk pasangan: nama barang dan stoknya, kata dan frekuensinya, ID dan nama pemiliknya. std::map<K, V> menyimpan pasangan itu dengan aturan yang sama dengan std::set — kunci unik dan selalu terurut — namun setiap kini kunci membawa satu nilai teman. Karena dibangun di atas pohon yang sama, pencarian, penyisipan, dan penghapusan bernilai O(log n) menurut jumlah entri. Pada Chapter ini kita menimbang tiga cara menyentuh isi map (operator[], at(), insert), membaca isinya dengan structured bindings, lalu melihat std::multimap yang memperbolehkan satu kunci memakai banyak nilai.
Tiga Cara Menyentuh Isi Map #
Cara ketiganya terlihat mirip, tetapi semantiknya berbeda dan salah pilih bisa berujung bug halus. Program berikut menunjukkan ketiganya berdampingan.
#include <iostream> // std::cout
#include <map> // std::map dan std::multimap
#include <string> // std::string
int main() {
// --- map: pasangan kunci -> nilai, terurut menurut kunci ---
std::map<std::string, int> stok;
stok["kopi"] = 12; // operator[]: buat bila kunci belum ada
stok["teh"] = 30;
stok["gula"] = 7;
stok["kopi"] -= 5; // akses lalu ubah nilainya
std::cout << "kopi tersisa: " << stok["kopi"] << "\n";
// HATI-HATI: membaca kunci yang belum ada MEMBUAT entri baru bernilai 0
std::cout << "cokelat (baru): " << stok["cokelat"] << "\n";
std::cout << "ukuran sekarang: " << stok.size() << "\n";
// at() menanyakan nilai tanpa membuat entri; melempar exception bila absen
std::cout << "teh via at(): " << stok.at("teh") << "\n";
// iterasi map: elemen berupa pair (kunci, nilai), selalu terurut menurut kunci
std::cout << "Daftar stok (terurut):\n";
for (const auto& [nama, jumlah] : stok) {
std::cout << " " << nama << " : " << jumlah << "\n";
}
// insert TIDAK menimpa bila kunci sudah ada
auto hasil = stok.insert({"teh", 99});
std::cout << "insert teh=99 berhasil: "
<< (hasil.second ? "ya" : "tidak") << "\n";
std::cout << "teh masih: " << stok.at("teh") << "\n";
// --- multimap: satu kunci boleh membawa banyak nilai ---
std::multimap<std::string, std::string> kontak;
kontak.insert({"budi", "[email protected]"});
kontak.insert({"budi", "[email protected]"});
kontak.insert({"siti", "[email protected]"});
std::cout << "Email budi (" << kontak.count("budi") << " entri):\n";
for (const auto& [nama, email] : kontak) {
if (nama == "budi") std::cout << " " << email << "\n";
}
return 0;
}Output yang Dihasilkan:
kopi tersisa: 7
cokelat (baru): 0
ukuran sekarang: 4
teh via at(): 30
Daftar stok (terurut):
cokelat : 0
gula : 7
kopi : 7
teh : 30
insert teh=99 berhasil: tidak
teh masih: 30
Email budi (2 entri):
[email protected]
[email protected]Mari kita bedah:
- Baris 8-10 (
operator[]): penugasan lewat kurung siku membuat entri bila kunci belum ada — cara paling ringkas menambah data.stok["kopi"] -= 5kemudian membaca dan mengubah nilai yang sudah ada. - Baris 16 (jebakan
operator[]): hanya membacastok["cokelat"]ternyata membuat entri baru bernilai0!operator[]tidak bisa membedakan maksud membaca dari menulis, sehinggasize()naik menjadi4— inilah bug halus yang paling sering dijumpai pemula. - Baris 20 (
at()):at()tidak pernah membuat entri. Bila kunci tidak ada, ia melempar exceptionstd::out_of_range(kita dalami di Section Error Handling) — jauh lebih aman untuk membaca ketika keberadaan kunci belum pasti. - Baris 24-26 (iterasi + structured bindings): setiap elemen map adalah
std::pairberisifirst(kunci) dansecond(nilai). Structured bindings yang kita pelajari pada Chapter Structured Bindings membongkarnya menjadinamadanjumlah, dan urutan keluar otomatis terurut:cokelat, gula, kopi, teh. - Baris 29-32 (
insert): berbeda darioperator[],inserttidak menimpa bila kunci sudah ada. Kembalianpair<iterator, bool>melaporberhasil=tidak, dan nilaitehtetap30. - Baris 35-43 (multimap): kunci
"budi"membawa dua email sekaligus. Karena multimap tidak punyaoperator[], penambahannya lewatinsert, dancount("budi")menghitung berapa banyak nilai yang menempel pada kunci itu.
Memilih antara operator[], at(), dan insert #
Tabel ini merangkum semantik ketiganya supaya keputusan kita cepat dan konsisten.
| Cara | Kunci belum ada | Kunci sudah ada | Cocok untuk |
|---|---|---|---|
m[k] = v | membuat entri | menimpa nilai | menambah/mengubah dengan sadar |
m.at(k) | melempar exception | membaca saja | membaca dengan aman |
m.insert({k, v}) | menambah | tidak menimpa | menambah tanpa merusak |
m[k] (baca) | membuat entri 0! | membaca | hindari untuk baca |
Satu pola umum yang sehat: gunakan m[k]++ untuk menghitung frekuensi (karena kita memang ingin entri baru mulai dari 0), gunakan at() untuk membaca, dan insert/emplace untuk mengisi data awal.
std::map memberi kita urutan kunci dan O(log n) untuk semua operasi. Chapter berikutnya membuka kandidat yang menukar urutan dengan kecepatan rata-rata O(1): std::unordered_set, pertama dari keluarga hash container.
Rujukan resmi: cppreference — std::map , cppreference — map::operator[] , cppreference — std::multimap .