Özel durum belirtimleri (throw, noexcept) (C++)

Özel durum belirtimleri, programcının bir işlev tarafından yayılabilir özel durum türleriyle ilgili amacını gösteren bir C++ dil özelliğidir. Özel durum belirtimi kullanarak bir işlevin özel durum tarafından çıkabileceğini veya çıkılmayabileceğini belirtebilirsiniz. Derleyici, işleve çağrıları iyileştirmek ve beklenmeyen bir özel durum işlevden kaçarsa programı sonlandırmak için bu bilgileri kullanabilir.

C++17'den önce iki tür özel durum belirtimi vardı. Noexcept belirtimi C++11'de yeniydi. İşlevden kaçabilecek olası özel durum kümesinin boş olup olmadığını belirtir. Dinamik özel durum belirtimi veya throw(optional_type_list) belirtimi, C++11'de kullanım dışı bırakıldı ve C++17'de kaldırıldı. Bunun dışındathrow(), diğer adıdırnoexcept(true). Bu özel durum belirtimi, bir işlevden hangi özel durumların oluşturulabileceği hakkında özet bilgi sağlamak üzere tasarlanmıştır, ancak uygulamada sorunlu olduğu bulunmuştur. Bir ölçüde yararlı olduğunu kanıtlayan tek dinamik özel durum belirtimi koşulsuz throw() belirtimdi. Örneğin, işlev bildirimi:

void MyFunction(int i) throw();

derleyiciye işlevin herhangi bir özel durum oluşturmadığını bildirir. Ancak, işlev bir özel durum oluşturursa, /std:c++14 modda bu tanımsız davranışa yol açabilir. Bu nedenle yukarıdaki yerine işlecini kullanmanızı noexcept öneririz:

void MyFunction(int i) noexcept;

Aşağıdaki tabloda özel durum belirtimlerinin Microsoft C++ uygulaması özetlemektedir:

Özel durum belirtimi Anlamı
noexcept
noexcept(true)
throw()
İşlev özel durum oluşturmaz. Modunda /std:c++14 (varsayılandır) noexcept ve noexcept(true) eşdeğerdir. veya noexcept(true)std::terminate bildirilen noexcept bir işlevden özel durum oluştuğunda çağrılır. Modda olarak throw() bildirilen bir işlevden özel durum oluştuğunda /std:c++14 sonuç tanımsız davranış olur. Belirli bir işlev çağrılmaz. Bu, derleyicinin çağırmasını std::unexpectedgerektiren C++14 standardının bir ayrılığıdır.
Visual Studio 2017 sürüm 15.5 ve üzeri: /std:c++17 modunda , noexcept, noexcept(true)ve throw() tüm eşdeğerleridir. modunda /std:c++17 , throw() için noexcept(true)bir diğer addır. Modunda ve sonraki sürümlerde /std:c++17 , bu belirtimlerden herhangi biriyle bildirilen bir işlevden özel durum oluştuğunda, std::terminate C++17 standardının gerektirdiği şekilde çağrılır.
noexcept(false)
throw(...)
Belirtim yok
işlevi herhangi bir türde özel durum oluşturabilir.
throw(type) (C++14 ve öncesi) İşlev türünde typebir özel durum oluşturabilir. Derleyici söz dizimini kabul eder, ancak olarak noexcept(false)yorumlar. Mod ve sonraki sürümlerde /std:c++17 , derleyici C5040 uyarısını verir.

Bir uygulamada özel durum işleme kullanılıyorsa, çağrı yığınında , noexcept(true)veya throw()olarak işaretlenmiş noexceptbir işlevin dış kapsamından çıkmadan önce oluşan özel durumları işleyen bir işlev olmalıdır. Özel durum oluşturan ile özel durumu işleyen arasında çağrılan işlevler , noexcept(true) (veya throw() modunda/std:c++17) olarak noexceptbelirtilirse, noexcept işlevi özel durumu yaydığında program sonlandırılır.

bir işlevin özel durum davranışı aşağıdaki faktörlere bağlıdır:

  • Hangi dil standart derleme modunun ayarlandığı.

  • İşlevi C veya C++ altında derleyip derlemediğiniz.

  • Hangi /EH derleyici seçeneğini kullandığınız.

  • Özel durum belirtimini açıkça belirtip belirtmediğiniz.

C işlevlerinde açık özel durum belirtimlerine izin verilmez. C işlevinin altında /EHscözel durumlar oluşturmadığı varsayılır ve , /EHaveya /EHacaltında /EHsyapılandırılmış özel durumlar atabilir.

Aşağıdaki tabloda, bir C++ işlevinin çeşitli derleyici özel durum işleme seçenekleri altında oluşturup oluşturmayabileceği özetlenmiştir:

Function /EHsc /EHs /EHa /EHac
Özel durum belirtimi olmayan C++ işlevi Evet Evet Evet Evet
, noexcept(true)veya throw() özel durum belirtimiyle noexceptC++ işlevi Hayır Hayı Evet Evet
, throw(...)veya throw(type) özel durum belirtimiyle noexcept(false)C++ işlevi Evet Evet Evet Evet

Örnek

// 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

Ayrıca bkz.

try, throwve catch Deyimleri (C++)
Özel durumlar ve hata işleme için modern C++ en iyi yöntemleri