Episode ini membahas fitur C++ modern: auto, range-based loops, dan structured bindings, move semantics dengan rvalue references, std::optional, std::variant, std::any, dan coroutines, serta modules, concepts, dan peningkatan constexpr.

C++ yang kalian pelajari dari buku lama dan C++ yang dipakai industri hari ini berbeda secara fundamental. Sejak C++11, bahasa ini bertransformasi: cara menulis yang lebih ringkas, manajemen memori yang lebih aman, dan fitur yang sebelumnya mustahil menjadi mungkin.
Episode 16 merangkum fitur modern paling berpengaruh: auto dan structured bindings yang membuat kode lebih pendek, move semantics yang menghilangkan salinan boros, std::optional dan std::variant yang mengekspresikan kemungkinan, constexpr yang memindahkan perhitungan ke kompilasi, serta coroutines dan modules yang mengubah cara program terstruktur.
auto membuat compiler menebak tipe dari inisialisasi. Di C++ modern, auto adalah default untuk variabel lokal — kode menjadi ringkas tanpa kehilangan keamanan tipe. auto& membuat reference, dan const auto& untuk baca-saja tanpa menyalin:
cat > modern1.cpp <<'EOF'
#include <iostream>
#include <map>
#include <string>
int main() {
std::map<std::string, int> nilai{{"A", 90}, {"B", 85}};
for (const auto& [nama, skor] : nilai) {
std::cout << nama << ": " << skor << "\n";
}
}
EOF
g++ -std=c++20 modern1.cpp -o modern1
./modern1for (const auto& [nama, skor] : nilai) adalah structured binding (C++17): loop range-based sekaligus membongkar pasangan key-value. Sebelum C++17, kalian harus menulis it->first dan it->second secara manual.
Range-based loop menyalin elemen secara default. Untuk elemen besar seperti string atau objek, gunakan const auto& agar tidak menyalin. Perbedaan satu huruf ini menentukan apakah program mengalokasikan memori terus-menerus atau tidak.
Lvalue adalah ekspresi yang punya alamat dan bisa diambil referensinya; rvalue adalah nilai sementara. Move semantics memindahkan resource dari objek yang akan segera dibuang ke objek baru, alih-alih menyalinnya. std::move mengubah lvalue menjadi rvalue:
cat > move.cpp <<'EOF'
#include <iostream>
#include <string>
#include <utility>
int main() {
std::string a = "data besar yang panjang sekali";
std::string b = std::move(a);
std::cout << "b: " << b << "\n";
std::cout << "a (kosong setelah move): " << a.size() << "\n";
}
EOF
g++ -std=c++20 move.cpp -o move
./movestd::string b = std::move(a) memindahkan buffer internal a ke b — operasi O(1) alih-alih menyalin seluruh string. Setelah move, a berada dalam kondisi valid tetapi tidak ditentukan, biasanya kosong. Move constructor dan move assignment adalah alasan std::vector bisa tumbuh tanpa membayar biaya salinan.
Kelas yang mengelola resource bisa mendefinisikan move constructor yang mencuri resource alih-alih menyalinnya. Compiler membuatnya otomatis saat semua member moveable. Ini salah satu alasan kode modern lebih cepat dari kode C++98 yang menyalin semuanya.
std::optional<T> menyatakan nilai yang mungkin tidak ada, std::variant<T1, T2> menyimpan satu nilai dari beberapa kemungkinan tipe, dan std::any menyimpan nilai tipe apa pun dengan biaya alokasi dinamis. Episode 10 membahas optional dan variant mendalam; di sini kalian melihat any:
cat > any.cpp <<'EOF'
#include <iostream>
#include <any>
int main() {
std::any nilai = 42;
std::cout << std::any_cast<int>(nilai) << "\n";
nilai = std::string("teks");
if (nilai.type() == typeid(std::string)) {
std::cout << std::any_cast<std::string>(nilai) << "\n";
}
}
EOF
g++ -std=c++20 any.cpp -o any
./anystd::any_cast<int>(nilai) mengambil nilai dari any jika tipenya cocok, dan melempar std::bad_any_cast jika tidak. Gunakan any dengan hemat — tipe yang tidak diketahui saat kompilasi biasanya pertanda desain yang bisa disederhanakan dengan variant.
constexpr membuat fungsi dan objek dihitung saat kompilasi bila memungkinkan. Sejak C++20, constexpr mendukung loop, std::vector, dan std::string, sehingga banyak perhitungan bisa dipindahkan dari runtime ke kompilasi:
cat > constexpr20.cpp <<'EOF'
#include <iostream>
#include <array>
constexpr int jumlah(const std::array<int, 3>& a) {
int total = 0;
for (int x : a) {
total += x;
}
return total;
}
int main() {
constexpr std::array<int, 3> data{10, 20, 30};
constexpr int hasil = jumlah(data);
std::cout << hasil << "\n";
}
EOF
g++ -std=c++20 constexpr20.cpp -o constexpr20
./constexpr20constexpr int hasil = jumlah(data) menjalankan jumlah saat kompilasi — hasilnya tertanam di biner tanpa biaya runtime sama sekali. Concepts (C++20) memberi nama pada persyaratan tipe, menggantikan SFINAE yang sulit dibaca, dan sudah dibahas di episode 10.
Coroutines (C++20) memungkinkan fungsi ditangguhkan dan dilanjutkan tanpa memblokir thread. co_await menunggu operasi asinkron, co_return mengembalikan hasil. Coroutines menjadi fondasi asynchronous I/O dan generator yang ringan:
#include <coroutine>
// co_await async_call(); // tunda tanpa memblokir thread
// co_return hasil; // selesaikan coroutinePemrograman coroutine membutuhkan tipe task dan awaiter yang tepat — cukup kompleks untuk dibahas khusus. Yang penting dipahami: coroutines memungkinkan ribuan operasi asinkron bersamaan tanpa ribuan thread, pola yang dipakai server modern dan game engine.
Modules (C++20) menggantikan #include dengan unit kompilasi yang mandiri. Modul mengekspor simbol secara eksplisit dengan export, dan hanya sekali dikompilasi alih-alih diproses ulang di setiap file yang menyertakannya:
cat > math.cppm <<'EOF'
export module math;
export int kali(int a, int b) {
return a * b;
}
EOF
g++ -std=c++20 -fmodules-ts math.cppm -o math.oexport module math; mendefinisikan modul, dan export int kali(...) mengekspos fungsi ke pemakai modul. Build dengan -fmodules-ts di GCC. Modules membuat kode lebih bersih daripada header dan mempercepat kompilasi proyek besar.
Info
Dukungan modules masih berkembang di compiler. Untuk proyek produksi, pastikan toolchain mendukung fitur yang dipakai sebelum beralih sepenuhnya dari header.
Inti yang harus dibawa pulang:
auto, range-based loop, dan structured binding membuat kode ringkas dan aman.std::move.optional, variant, dan any mengekspresikan kemungkinan nilai secara eksplisit.constexpr memindahkan perhitungan ke waktu kompilasi.Di episode 17 selanjutnya kita akan membahas architecture dan design patterns — pola factory, singleton, dan observer, dependency injection, adapter, dan decorator, domain-driven design dan layered architecture, serta modularization untuk organisasi kode skala besar.