Setelah empat chapter hidup dengan kelemahan array C-style — tidak tahu ukurannya sendiri, meluruh jadi pointer, tidak bisa disalin — waktunya bertemu solusi standar: std::array. Tipe ini didefinisikan pada header <array> dan membungkus array C-style biasa dengan antarmuka modern. Dalam hal tata letak memori, std::array identik dengan array C-style: elemen-elemennya contiguous dan ukurannya tetap, sehingga kecepatannya tidak berkurang sama sekali — sifat zero-cost abstraction yang disebut pada Section Pengenalan C++. Pada Chapter ini kita mempelajari penggunaan std::array, perbedaan dua cara aksesnya (operator[] dan .at()), dan memetakan keunggulannya dibanding array C-style.

Penggunaan Dasar std::array #

Deklarasinya memakai dua parameter: tipe elemen dan ukuran, keduanya ditulis di dalam kurung siku tipe — std::array<int, 5>. Karena ukuran menjadi bagian dari tipe, compiler selalu tahu array ini sepanjang apa, di mana pun ia berada. Program berikut memperagakan anggota-anggota yang paling sering dipakai:

cpp
#include <array>
#include <iostream>
#include <stdexcept>

int main() {
    std::array<int, 5> data = {3, 6, 9, 12, 15};

    // ukuran melekat pada tipe: .size() selalu benar, tidak perlu sizeof
    std::cout << "ukuran: " << data.size() << "\n";

    // operator[] — cepat, tanpa pemeriksaan batas (sama seperti array C-style)
    data[0] = 30;
    std::cout << "data[0] setelah diubah: " << data[0] << "\n";

    // .at() — mengakses dengan pemeriksaan batas
    std::cout << "data.at(4) = " << data.at(4) << "\n";

    // .at(10) berada di luar batas: exception dilempar dan kita tangkap
    try {
        std::cout << data.at(10) << "\n";  // baris ini tidak sempat tercetak
    } catch (const std::out_of_range& e) {
        std::cout << "Tertangkap: " << e.what() << "\n";
    }

    // fill: isi semua elemen dengan satu nilai yang sama
    data.fill(7);
    std::cout << "setelah fill(7)  : ";
    for (std::size_t i = 0; i < data.size(); ++i) {
        std::cout << (i > 0 ? " " : "") << data[i];
    }
    std::cout << "\n";

    // salin-assign antara dua std::array yang sama tipenya
    std::array<int, 5> lain = {};
    lain = data;
    std::cout << "salinan berisi   : " << lain.front() << " dan "
              << lain.back() << "\n";

    return 0;
}

Output yang Dihasilkan:

text
ukuran: 5
data[0] setelah diubah: 30
data.at(4) = 15
Tertangkap: array::at: __n (which is 10) >= _Nm (which is 5)
setelah fill(7)  : 7 7 7 7 7
salinan berisi   : 7 dan 7

Mari kita bedah:

  1. Baris 8 (std::array<int, 5> data = {3, 6, 9, 12, 15};): initializer list yang sama dengan array C-style berfungsi di sini, dan ukuran 5 ikut tertulis pada tipe. Ada juga anggota .size() yang mengembalikan jumlah elemen — tidak perlu lagi sizeof dibagi sizeof.
  2. Baris 11-13 (data[0]): operator[] berperilaku persis seperti kurung siku array C-style — akses tercepat, tanpa pemeriksaan batas. Indeks di luar batas melalui jalur ini tetap undefined behavior.
  3. Baris 16-23 (.at()): anggota .at(i) melakukan akses yang sama tetapi memeriksa batas terlebih dahulu. Bila indeks melampaui .size(), ia melempar exception — mekanisme laporan kesalahan runtime yang dibedah tuntas pada Section Error Handling. Di sini kita menangkapnya dengan try/catch agar program tetap berjalan dan bisa mencetak pesan dari .what().
  4. Baris 26 (data.fill(7);): mengisi seluruh elemen dengan satu nilai — pemasangan 7 ke lima slot sekaligus. Fungsionalitas semacam ini tidak dimiliki array C-style.
  5. Baris 33-34 (lain = data;): penugasan antar std::array yang sama tipenya menyalin seluruh elemen, bukan sekadar alamat. Array C-style bahkan tidak bisa ditulis a = b; sama sekali.
  6. Baris 35-36 (.front(), .back()): pembaca ringkas untuk elemen pertama dan terakhir — front() setara data[0], back() setara data[data.size() - 1].

operator[] vs .at(): Kecepatan atau Pemeriksaan #

std::array menawarkan dua pintu akses yang sama-sama sah, dengan pertimbangan berbeda:

Aspekdata[i]data.at(i)
Pemeriksaan batasTidak adaAda (melempar std::out_of_range)
Biaya saat indeks salahUndefined behaviorBerhenti dengan pesan yang jelas
Kecepatan pada jalur normalPaling cepatCepat, ditambah satu perbandingan
Cocok untukLoop yang batasnya sudah benarIndeks dari sumber luar (input, berkas, hasil perhitungan)

Praktik yang sehat: gunakan operator[] di dalam loop yang batasnya kita kendalikan penuh, dan .at() saat indeks berasal dari luar kendali program. Dengan begitu kesalahan sumber data berubah menjadi pesan yang jelas, bukan perilaku tak terdefinisi yang senyap.

Perbandingan dengan Array C-Style #

Tabel berikut merangkum mengapa std::array menjadi pilihan utama untuk ukuran tetap:

AspekArray C-style int a[5]std::array<int, 5>
Mengetahui ukuran sendiriTidak (harus sizeof manual, hanya di tempat deklarasi)Ya, .size() bekerja di mana pun
Menjadi parameter fungsiMeluruh menjadi pointer (ukuran hilang)Ukuran melekat pada tipe, tetap terbawa
Penyalinan b = a;Tidak bisa ditulis langsungBisa; menyalin seluruh elemen
Dikembalikan dari fungsiTidak bisa secara langsungBisa, sebagai nilai kembalian biasa
Akses berbatas .at()Tidak adaAda
Antar-muka pustaka standarTerbatasKompatibel penuh (dapat diiterasi, dipakai algoritma)
Tata letak memori dan kecepatanContiguous, tercepatIdentik — membungkus array C-style

Poin terakhir itu penting untuk tenang: std::array bukan “array lambat versi aman”. Ia hanyalah pembungkus tipis; setelah kompilasi, kode aksesnya dibangkitkan sama persis dengan array C-style. Kita kehilangan tidak apa-apa, kecuali dua hal kecil: ukuran harus tetap konstanta waktu kompilasi (sama seperti array C-style), dan sintaksnya sedikit lebih panjang.

Dengan std::array menutup kasus ukuran tetap, sisa section ini berpindah ke dunia teks. Chapter berikutnya membahas C-style string — array char dengan aturan khusus — sebelum std::string mengambil alih dengan cara yang jauh lebih nyaman.

Rujukan resmi: cppreference — std::array , cppreference — std::array::at .