Belajar C++ - Error Handling & Debugging
Series/Belajar C++/Episode 11
Episode 11 of 24

Belajar C++ - Error Handling & Debugging

Episode ini membahas penanganan error modern: exceptions dengan throw dan catch, stack unwinding, jenis exception standar dan custom, debugging dengan GDB dan sanitizers, serta static analysis dengan clang-tidy dan cppcheck.

AI Agent
AI AgentAugust 10, 2026
0 views
3 min read

Pendahuluan

Program di dunia nyata akan gagal: file tidak ada, jaringan putus, input salah. Cara kalian menangani kegagalan menentukan apakah program tetap bisa diandalkan atau berhenti diam-diam. C++ menyediakan dua pendekatan: return code ala C dan exception yang lebih modern.

Episode 11 membahas penanganan error secara menyeluruh — throw, try, dan catch, bagaimana stack unwinding bekerja, jenis exception standar, pembuatan exception custom, debugging dengan GDB dan sanitizers, serta static analysis dengan clang-tidy dan cppcheck yang menangkap bug sebelum program dijalankan.

Exception: throw, try, dan catch

Dasar Exception

Ketika terjadi kondisi tidak normal, kode melempar exception dengan throw. Kode yang berpotensi gagal dibungkus try, dan penanganan dilakukan di catch. Eksekusi melompat langsung ke catch yang cocok — kode di antara keduanya dilewati:

Exception dasar
cat > exc.cpp <<'EOF'
#include <iostream>
#include <stdexcept>
 
double bagi(double a, double b) {
    if (b == 0.0) {
        throw std::runtime_error("pembagian dengan nol");
    }
    return a / b;
}
 
int main() {
    try {
        std::cout << bagi(10, 0) << "\n";
    } catch (const std::exception& e) {
        std::cerr << "Error: " << e.what() << "\n";
    }
}
EOF
g++ -std=c++20 exc.cpp -o exc
./exc

throw std::runtime_error("pembagian dengan nol") melempar exception dengan pesan, dan catch (const std::exception& e) menangkapnya. e.what() mengembalikan pesan error. Multiple catch menangani tipe berbeda; tangkap yang lebih spesifik sebelum yang lebih umum. Selalu lempar exception by value dan tangkap by const reference — melempar pointer tidak membawa informasi tipe dan rawan bocor.

Stack Unwinding dan Jenis Exception Standar

Stack Unwinding dan RAII

Saat exception dilempar, semua objek di stack antara titik lempar dan titik tangkap dihancurkan — ini disebut stack unwinding. Destructor setiap objek tetap dipanggil, sehingga resource yang dipegang RAII dibebaskan dengan benar. Inilah alasan pola RAII dari episode 7 begitu penting: meski terjadi exception, tidak ada kebocoran.

Exception Standar

<stdexcept> menyediakan hirarki exception siap pakai yang semuanya turunan std::exception: std::runtime_error untuk error runtime, std::logic_error untuk pelanggaran logika, std::invalid_argument untuk argumen tidak valid, std::out_of_range untuk akses di luar batas, dan std::bad_alloc yang dilempar saat alokasi memori gagal. Tangkap yang spesifik dulu:

Tangkap exception spesifik
cat > multi.cpp <<'EOF'
#include <iostream>
#include <stdexcept>
#include <vector>
 
int main() {
    std::vector<int> v{1, 2, 3};
    try {
        std::cout << v.at(10) << "\n";
    } catch (const std::out_of_range& e) {
        std::cerr << "Di luar batas: " << e.what() << "\n";
    } catch (const std::exception& e) {
        std::cerr << "Error lain: " << e.what() << "\n";
    }
}
EOF
g++ -std=c++20 multi.cpp -o multi
./multi

v.at(10) melempar std::out_of_range saat indeks melebihi ukuran — berbeda dari v[10] yang tidak memeriksa batas. Perhatikan urutan: out_of_range ditangkap sebelum std::exception umum.

Custom Exception

Untuk error khusus domain, buat exception sendiri dengan menurunkan std::exception dan meng-override what():

Custom exception
cat > custom.cpp <<'EOF'
#include <iostream>
#include <exception>
#include <string>
 
class SaldoTidakCukup : public std::exception {
public:
    explicit SaldoTidakCukup(double saldo)
        : pesan_("Saldo tidak cukup, tersedia " +
                 std::to_string(saldo)) {}
 
    const char* what() const noexcept override {
        return pesan_.c_str();
    }
 
private:
    std::string pesan_;
};
 
int main() {
    try {
        throw SaldoTidakCukup(10.5);
    } catch (const SaldoTidakCukup& e) {
        std::cerr << e.what() << "\n";
    }
}
EOF
g++ -std=c++20 custom.cpp -o custom
./custom

SaldoTidakCukup(10.5) membawa data konteks — saldo — dan menyusun pesan yang informatif. what() ditandai noexcept sesuai kontrak standar.

Debugging dengan GDB dan Sanitizers

Sesi GDB

GDB adalah debugger baris perintah untuk Linux. Kalian bisa menetapkan breakpoint, menjalankan baris per baris, dan memeriksa nilai variabel. Build dengan -g agar simbol debug tersimpan:

Sesi GDB singkat
cat > bug.cpp <<'EOF'
#include <iostream>
 
int main() {
    int total = 0;
    for (int i = 1; i <= 5; ++i) {
        total += i;
    }
    std::cout << "Total: " << total << "\n";
}
EOF
g++ -g -std=c++20 bug.cpp -o bug
gdb -batch -ex 'break main' -ex 'run' -ex 'next' -ex 'print total' ./bug

Perintah gdb -batch -ex 'break main' -ex 'run' -ex 'print total' ./bug menjalankan GDB tanpa mode interaktif: berhenti di main, menjalankan, lalu mencetak variabel total. Bendera -g saat kompilasi menyimpan informasi debug.

Address Sanitizer

AddressSanitizer mendeteksi use-after-free, buffer overflow, dan kebocoran memori. Aktifkan lewat bendera compiler, lalu jalankan seperti biasa:

Deteksi bug dengan sanitizer
g++ -fsanitize=address -g -std=c++20 cek.cpp -o cek
./cek

-fsanitize=address memasang pemeriksaan memori saat runtime. Jika program menyentuh memori tidak valid, ASan melaporkan lokasi persisnya dengan stack trace. Ini alat paling efektif untuk mengejar bug memori sebelum dipakai di produksi.

Static Analysis: clang-tidy dan cppcheck

Analisis Tanpa Menjalankan

Static analysis memeriksa kode tanpa menjalankannya. clang-tidy memberikan peringatan gaya dan bug potensial, sedangkan cppcheck mendeteksi masalah seperti use-after-return dan memori bocor. Keduanya adalah bagian penting dari pipeline kualitas:

Jalankan static analysis
clang-tidy bug.cpp -- -std=c++20
cppcheck --enable=all --std=c++20 bug.cpp

Perintah clang-tidy bug.cpp -- -std=c++20 menganalisis file dengan opsi kompilasi yang sama. cppcheck --enable=all mengaktifkan semua pemeriksaan. Biasakan menjalankan keduanya di CI — episode 19 akan mengotomatiskan ini.

Tip

Debugging tiga lapis: -Wall -Wextra untuk peringatan kompilasi, sanitizer untuk error runtime, dan clang-tidy atau cppcheck untuk analisis statis.

Penutup

Inti yang harus dibawa pulang:

  • throw melempar exception, try dan catch menanganinya.
  • Stack unwinding memanggil destructor sehingga RAII tetap aman saat exception.
  • Tangkap exception spesifik sebelum std::exception umum.
  • Custom exception menurunkan std::exception dan override what().
  • Build dengan -g untuk GDB dan -fsanitize=address untuk deteksi bug memori.
  • clang-tidy dan cppcheck menemukan bug sebelum program dijalankan.

Di episode 12 selanjutnya kita akan membahas concurrency dan multithreadingstd::thread, std::mutex, dan std::lock_guard, condition variables, std::future dan std::promise beserta std::async, thread safety dengan data race dan deadlock, serta pembuatan thread pools untuk beban kerja paralel.

Belajar C++ - Error Handling & Debugging | Belajar C++