Spesifikasi pengecualian (throw, noexcept) (C++)

Spesifikasi pengecualian adalah fitur bahasa C++ yang menunjukkan niat programmer tentang jenis pengecualian yang dapat disebarluaskan oleh fungsi. Anda dapat menentukan bahwa fungsi mungkin atau mungkin tidak keluar dengan pengecualian dengan menggunakan spesifikasi pengecualian. Pengkompilasi dapat menggunakan informasi ini untuk mengoptimalkan panggilan ke fungsi, dan untuk mengakhiri program jika pengecualian yang tidak terduga lolos dari fungsi.

Sebelum C++17 ada dua jenis spesifikasi pengecualian. Spesifikasi noexcept baru di C++11. Ini menentukan apakah kumpulan pengecualian potensial yang dapat lolos dari fungsi kosong. Spesifikasi pengecualian dinamis, atau throw(optional_type_list) spesifikasi, tidak digunakan lagi di C++11 dan dihapus di C++17, kecuali untuk throw(), yang merupakan alias untuk noexcept(true). Spesifikasi pengecualian ini dirancang untuk memberikan informasi ringkasan tentang pengecualian apa yang dapat dibuang dari fungsi, tetapi dalam praktiknya ditemukan bermasalah. Satu spesifikasi pengecualian dinamis yang terbukti agak berguna adalah spesifikasi yang tidak bersyarat throw() . Misalnya, deklarasi fungsi:

void MyFunction(int i) throw();

memberi tahu pengkompilasi bahwa fungsi tidak melemparkan pengecualian apa pun. Namun, dalam /std:c++14 mode ini dapat menyebabkan perilaku yang tidak ditentukan jika fungsi melemparkan pengecualian. Oleh karena itu, sebaiknya gunakan noexcept operator alih-alih operator di atas:

void MyFunction(int i) noexcept;

Tabel berikut ini meringkas implementasi Microsoft C++ dari spesifikasi pengecualian:

Spesifikasi pengecualian Makna
noexcept
noexcept(true)
throw()
Fungsi ini tidak melemparkan pengecualian. Dalam /std:c++14 mode (yang merupakan default), noexcept dan noexcept(true) setara. Ketika pengecualian dilemparkan dari fungsi yang dinyatakan noexcept atau noexcept(true), std::terminate dipanggil. Ketika pengecualian dilemparkan dari fungsi yang dinyatakan sebagai throw() dalam /std:c++14 mode, hasilnya adalah perilaku yang tidak ditentukan. Tidak ada fungsi khusus yang dipanggil. Ini adalah divergensi dari standar C++14, yang mengharuskan pengkompilasi untuk memanggil std::unexpected.
Visual Studio 2017 versi 15.5 dan yang lebih baru: Dalam /std:c++17 mode , , noexceptnoexcept(true), dan throw() semuanya setara. Dalam /std:c++17 mode, throw() adalah alias untuk noexcept(true). Dalam /std:c++17 mode dan yang lebih baru, ketika pengecualian dilemparkan dari fungsi yang dideklarasikan dengan salah satu spesifikasi ini, std::terminate dipanggil sebagaimana diperlukan oleh standar C++17.
noexcept(false)
throw(...)
Tidak ada spesifikasi
Fungsi ini dapat melemparkan pengecualian dari jenis apa pun.
throw(type) (C++14 dan yang lebih lama) Fungsi dapat melemparkan pengecualian jenis type. Pengkompilasi menerima sintaks, tetapi menafsirkannya sebagai noexcept(false). Dalam /std:c++17 mode dan yang lebih baru, kompilator mengeluarkan peringatan C5040.

Jika penanganan pengecualian digunakan dalam aplikasi, harus ada fungsi dalam tumpukan panggilan yang menangani pengecualian yang dilemparkan sebelum keluar dari cakupan luar fungsi yang ditandai noexcept, , noexcept(true)atau throw(). Jika ada fungsi yang dipanggil antara fungsi yang melempar pengecualian dan yang menangani pengecualian ditentukan sebagai noexcept, (atau throw() dalam mode), program dihentikan /std:c++17 ketika fungsi noexcept noexcept(true) menyebarkan pengecualian.

Perilaku pengecualian fungsi tergantung pada faktor-faktor berikut:

  • Mode kompilasi standar bahasa mana yang diatur.

  • Apakah Anda mengkompilasi fungsi di bawah C atau C++.

  • Opsi pengkompilasi mana yang /EH Anda gunakan.

  • Apakah Anda secara eksplisit menentukan spesifikasi pengecualian.

Spesifikasi pengecualian eksplisit tidak diizinkan pada fungsi C. Fungsi C diasumsikan untuk tidak melemparkan pengecualian di bawah /EHsc, dan dapat melemparkan pengecualian terstruktur di bawah /EHs, , /EHaatau /EHac.

Tabel berikut ini meringkas apakah fungsi C++ mungkin berpotensi dilemparkan di bawah berbagai opsi penanganan pengecualian kompilator:

Function /EHsc /EHs /EHa /EHac
Fungsi C++ tanpa spesifikasi pengecualian Ya Ya Ya Ya
Fungsi C++ dengan noexceptspesifikasi pengecualian , noexcept(true), atau throw() Tidak No Ya Ya
Fungsi C++ dengan noexcept(false)spesifikasi pengecualian , throw(...), atau throw(type) Ya Ya Ya Ya

Contoh

// exception_specification.cpp
// compile with: /EHs
#include <stdio.h>

void handler() {
   printf_s("in handler\n");
}

void f1(void) throw(int) {
   printf_s("About to throw 1\n");
   if (1)
      throw 1;
}

void f5(void) throw() {
   try {
      f1();
   }
   catch(...) {
      handler();
    }
}

// invalid, doesn't handle the int exception thrown from f1()
// void f3(void) throw() {
//   f1();
// }

void __declspec(nothrow) f2(void) {
   try {
      f1();
   }
   catch(int) {
      handler();
    }
}

// only valid if compiled without /EHc
// /EHc means assume extern "C" functions don't throw exceptions
extern "C" void f4(void);
void f4(void) {
   f1();
}

int main() {
   f2();

   try {
      f4();
   }
   catch(...) {
      printf_s("Caught exception from f4\n");
   }
   f5();
}
About to throw 1
in handler
About to throw 1
Caught exception from f4
About to throw 1
in handler

Baca juga

try, throw, dan catch Pernyataan (C++)
Praktik terbaik C++ modern untuk pengecualian dan penanganan kesalahan