C++ İle Exception
metod imzasında throw
exception specification C++11 ile kullanımdan kaldırıldı. metodun imzasına throw ile atabileceği exceptionları yazmanın anlamı yok. Yeni kodlarda throw yazmak yerine açıklama yazılmalı.
metod imzasında noexcept kullanılmaya devam edilebilir.
Exception nerede yaşar
Standarttaki açıklama şöyle.
Stackteki exception bu özel alana nasıl taşınır
Bu açıklama sanırım pointer olarak fırlatılmayan exception nesneleri için geçerli. Kendi kodumuzdaki exception nesnesinin, bu özel alandaki Exception nesnesine atanması tamamen derleyicinin nasıl kod ürettiğine bağlı. Kopyalama (gerekiyorsa) işleminin olabilmesi için bazı metodların erişilebiliyor olması lazım.
Mesela Visual Studio 2013 kopyalama yöntemini kullanıyor. Dolayısıyla kendi exception nesnemizin destructor metodunun iki defa çağrıldığını görebiliriz. GCC ise başka bir kod üretiyor.
Static exception nesnesi
more effective c++ Item no -13'te metod içindeki static exception nesnesi örneği var.
Kendi Exception Sınıfımız yazısına taşıdm.
STL İçinde Tanımlı exceptionlar
C++ ile gelen tanımlı exceptionları şunlar
std::exception sınıfı
std::exception Sınıfı yazısına taşıdım.
std::runtime_error
Exception hiyerarşimiz varsa, fırlatılan exception'ı referans olarak yakalamak gerekir. Örnek:
Aşağıdak kod parçası çıktı olarak "NullPointerException" yerine "Exception" yazar.
Exception ve finally
Java, C# gibi dillerde exception try/catch/finally şeklinde kullanılıyor. Bu kullanım şekli eğer dilin içinde deterministic destructor yoksa faydalı. C++'ta RAII - yani constructor da kaynağı al, destructor da bırak - olduğu için pek tercih edilmiyor.
Exception ve macro
Macro sadece exception mesajı içine dosya ve satır numarası konulacaksa kullanılmalı.
Ancak function-like macro şeklinde olmamalı. Yanlış bir örnek
throw ile Exception'ı Tekrar Fırlatma yazısına taşıdım.
Exception ve Catch Sırası
Açıklaması şöyle.
gcc'de exception üç nokta ile yakalansa bile ismine erişme imkanı var. cxxabi.h ile abi namespace içindeki __cxa_exception_type()->name() ile exception ismi alınır.
metod imzasında throw
exception specification C++11 ile kullanımdan kaldırıldı. metodun imzasına throw ile atabileceği exceptionları yazmanın anlamı yok. Yeni kodlarda throw yazmak yerine açıklama yazılmalı.
/**
* Some function description.
*
* @throws SomeException In this or that situation this function will thrown an
* exception of type SomeException.
*/
void Foo();
metod imzasında noexcept kullanılmaya devam edilebilir.
Exception nerede yaşar
Standarttaki açıklama şöyle.
Yani exception nesnesi fırlatıldıktan sonra runtime'da özel bir alanda yaşar.[except.throw] 15.1/4: The memory for the exception object is allocated in an unspecified way, except as noted in 3.7.4.1. The exception object is destroyed after either the last remaining active handler for the exception exits by any means other than rethrowing, or the last object of type std::exception_ptr (18.8.5) that refers to the exception object is destroyed, whichever is later.
Stackteki exception bu özel alana nasıl taşınır
Bu açıklama sanırım pointer olarak fırlatılmayan exception nesneleri için geçerli. Kendi kodumuzdaki exception nesnesinin, bu özel alandaki Exception nesnesine atanması tamamen derleyicinin nasıl kod ürettiğine bağlı. Kopyalama (gerekiyorsa) işleminin olabilmesi için bazı metodların erişilebiliyor olması lazım.
15.1/5 When the thrown object is a class object, the constructor selected for the copy-initialization and the destructor shall be accessible, even if the copy/move operation is elided (12.8).
Mesela Visual Studio 2013 kopyalama yöntemini kullanıyor. Dolayısıyla kendi exception nesnemizin destructor metodunun iki defa çağrıldığını görebiliriz. GCC ise başka bir kod üretiyor.
// throw MyError("hi"); expands to:
auto tmp1 = MyError("hi");
auto exceptionObject = std::move(tmp1);
tmp1.~MyError(); //1. Destructor
goto catch;
// catch expands to:
MyError& exc = exceptionObject;
cout << exc.what() << endl;
// } of catch handler expands to:
exceptionObject.~MyError(); //2. Destructor
more effective c++ Item no -13'te metod içindeki static exception nesnesi örneği var.
void someFunction()Kendi exception sınıfımız
{
static exception ex; // exception object
...
throw &ex; // throw a pointer to ex
...
}
Kendi Exception Sınıfımız yazısına taşıdm.
STL İçinde Tanımlı exceptionlar
C++ ile gelen tanımlı exceptionları şunlar
std::exception sınıfı
std::exception Sınıfı yazısına taşıdım.
std::runtime_error
Exception hiyerarşimiz varsa, fırlatılan exception'ı referans olarak yakalamak gerekir. Örnek:
catch(const Exception& e)
Aksi takdirde exception slicing'e maruz kalırız. Bu tabir exception içindeki virtual metodların kullanılamaması anlamına gelir.Aşağıdak kod parçası çıktı olarak "NullPointerException" yerine "Exception" yazar.
#include <iostream>
class Exception{
public:
virtual void print(){
std::cerr << "Exception\n";
}
};
class NullPointerException : public Exception{
public:
void print(){
std::cerr << "NullPointerException\n";
}
};
int main(){
try{
throw NullPointerException();
}catch(Exception e){
e.print();
}
return 0;
}
Exception ve finally
Java, C# gibi dillerde exception try/catch/finally şeklinde kullanılıyor. Bu kullanım şekli eğer dilin içinde deterministic destructor yoksa faydalı. C++'ta RAII - yani constructor da kaynağı al, destructor da bırak - olduğu için pek tercih edilmiyor.
Exception ve macro
Macro sadece exception mesajı içine dosya ve satır numarası konulacaksa kullanılmalı.
Ancak function-like macro şeklinde olmamalı. Yanlış bir örnek
#define __EXCEPTION(aMessage) \
{ \
std::ostringstream stream; \
stream << "EXCEPTION: "<<aMessage<< ", file "<<__FILE__<< " line "<< __LINE__; \
throw ExceptionImpl(stream.str()); \
}
Inline metod kullanan daha iyi bir örnek#define MY_EXCEPTION(aMessage) MyException(aMessage, __FILE__, __LINE__)
inline void MyException(const std::string aMessage,
const char* fileName,
const std::size_t lineNumber)
{
std::ostringstream stream;
stream << "EXCEPTION:"<<aMessage <<",file"<< fileName << " line " << lineNumber;
throw ExceptionImpl(stream.str());
}
Exception'ı Tekrar Fırlatmathrow ile Exception'ı Tekrar Fırlatma yazısına taşıdım.
Exception ve Catch Sırası
Açıklaması şöyle.
Exception ve Catch(...)The handlers for a try block are tried in order of appearance. That makes it possible to write handlers that can never be executed, for example by placing a handler for a derived class after a handler for a corresponding base class.
gcc'de exception üç nokta ile yakalansa bile ismine erişme imkanı var. cxxabi.h ile abi namespace içindeki __cxa_exception_type()->name() ile exception ismi alınır.
#include <cxxabi.h>
// more code here
} catch (...) {
std::string exName(abi::__cxa_current_exception_type()->name());
std::cout<<"unknown exception: "<< exName <<std::endl;
throw;
}
Hiç yorum yok:
Yorum Gönder