Pobierz prezentację
Pobieranie prezentacji. Proszę czekać
1
Bezpieczeństwo wyjątków w C++: OpenGL
Krzysztof Czaiński Opiekun pracy: dr inż. Cezary Stępień Krzysztof Czaiński
2
Motywacja Dużo literatury o OpenGL
The Red Book (Addison-Wesley) Dobrze opisane bezpieczeństwo wyjątków w C++ Exceptional C++, Herb Sutter OpenGL i wyjątki? GLT ( ) Building an OpenGL C++ Class, Dale Rogerson Krzysztof Czaiński
3
Plan prezentacji Dlaczego wyjątki? Bezpieczeństwo wyjątków w C++
Inne sposoby traktowania błędów Bezpieczeństwo wyjątków w C++ Gdzie wstawić bloki try / catch, czy coś więcej? OpenGL, a wyjątki Więcej o bezpieczeństwie wyjątków Krzysztof Czaiński
4
Obsługa błędów, czyli problem komunikacji
Autor klasy (biblioteki) może wykryć błąd, ale nie wie, co z nim zrobić Użytkownik klasy (biblioteki) wie, co zrobić z błędem, lecz nie potrafi go wykryć Przykłąd: Vector, odwołanie do nieistniejącego elementu. Krzysztof Czaiński Źródło: Materiały ZPR dr inż. Robert Nowaka
5
Sposoby traktowania błędów
Wady Ignorowanie Zakończenie programu Komunikat dla użytkownika Kod powrotu Zmienna globalna Specjalny stan obiektu Rezerwacja zwracanej wartości Użytkownik może zignorować błąd Kod obsługi wymieszany z innym kodem Obiekt globalny – potencjalne źródło kłopotów Krzysztof Czaiński Źródło: Materiały ZPR dr inż. Robert Nowaka
6
Mechanizm wyjątków a zasoby
void funkcja() { A* a = NULL; try{a = new A; // Kod rzucający delete a; } catch ( ... ) { delete a; throw; } class A {/*...*/}; void funkcja() { A* a = new A; // Kod rzucający delete a; } Niewygodne, nieczytelne, 2xnieefektywne Krzysztof Czaiński
7
Zdobywanie zasobów jest inicjalizacją (RAII)
Konstrukcja obiektu jest połączona ze zdobyciem zasobu Destrukcja obiektu jest połączona ze zwolnieniem zasobu Gdy obiekt jest lokalny, zasób jest zwalniany automatycznie w momencie niszczenia obiektu Krzysztof Czaiński
8
Sprytny wskaźnik template< typename X > class AutoPtr { public:
explicit AutoPtr( X* p = NULL ) : p_( p ) {} ~AutoPtr() { delete p_; } X& operator*() const { return *p_; } X* operator->() const { return p_; } private: X* p_; }; Możemy używać jak zwykłego wskaźnika. Uwaga: wszystkie metody throw() Krzysztof Czaiński
9
Użycie sprytnego wskaźnika
class A {/*...*/}; void funkcja() { AutoPtr<A> a( new A ); // Kod rzucający a->metoda(); AutoPtr<A> b = a; // ??? } Co z kopiowaniem? Jak widać, bezpieczeństwo wyjątków jest czymś więcej, niż „gdzie wstawić bloki try/catch. Wręcz „jak unikać bloków try/catch”. Krzysztof Czaiński
10
Przykładowy kod z OpenGL
void render() { double v[3]; glBegin( GL_TRIANGLES ); for ( int i = 0 ; i < n ; ++i ) getVertex( i, v ); // rzuca? glVertex3dv( v ); } glEnd(); Krzysztof Czaiński
11
Automatyczny glBegin/glEnd
#include <boost/utility.hpp> : boost::noncopyable struct Begin { explicit Begin( GLenum mode ) glBegin( mode ); } ~Begin() glEnd(); }; Pytanie: jak zrobić niekopiowalność? Krzysztof Czaiński
12
Przykładowy kod z bezpiecznymi wyjątkami
void render() { double v[3]; Begin( GL_TRIANGLES ); for ( int i = 0 ; i < n ; ++i ) getVertex( i, v ); // rzuca? OK. glVertex3dv( v ); } uważać na Begin(); Krzysztof Czaiński
13
Przykładowy kod z bezpiecznymi wyjątkami (2)
void render() { double v[3]; Begin begin( GL_TRIANGLES ); for ( int i = 0 ; i < n ; ++i ) getVertex( i, v ); // rzuca? OK. glVertex3dv( v ); } Krzysztof Czaiński
14
Zachowanie stanu OpenGL-a
void select() { glRenderMode( GL_SELECT ); // kod rzucający int hits = glRenderMode( GL_RENDER ); //... } Chcemy zagwarantować, żeby po wywołaniu select() OpenGL pozostał w trybie GL_RENDER Krzysztof Czaiński
15
Automatyczny glRenderMode
class RenderMode : boost::noncopyable { public: RenderMode( GLenum mode, GLenum restoreMode ) : restoreMode_(restoreMode), restored_(false) { glRenderMode( mode ); } ~RenderMode() { restoreRenderMode(); } GLint restoreRenderMode() { GLint result = 0; if ( ! restored_ ) { restored_ = true; result = glRenderMode( restoreMode_ ); } return result; private: GLenum restoreMode_; bool restored_; }; Krzysztof Czaiński
16
Zachowanie stanu OpenGL-a z auto- glRenderMode
void select() { RenderMode x( GL_SELECT, GL_RENDER ); // kod rzucający int hits = x.restoreRenderMode(); //... } Krzysztof Czaiński
17
Co to znaczy bezpieczeństwo wyjątków?
Gwarancje bezpieczeństwa wyjątków wg Dave’a Abrahama: Podstawowa: Brak wycieku zasobów Wszystkie obiekty pozostają w stanie używalnym, ale nie koniecznie przewidywalnym Silna: Gdy wystąpi wyjątek, stan programu pozostaje niezmieniony Nothrow: Nigdy nie rzuca Czyli po prostu „there are no bugs” - Herb Sutter. Np. Container::AppendElements() global commit-or-rollback semantics Niektóre funkcje muszą zapewniać, aby umożliwić powyższe gwarancje. Np. Destruktory, operacje dealokacji. Operacje auto_ptr są nothrow. Która w przypadku kodu z OpenGL? Krzysztof Czaiński Źródło: GotW #61
18
Korzyści Programowanie bezpieczne z uwzględnieniem wyjątków ma istotne zalety: Użytkownik klasy (biblioteki) może używać mechanizmu wyjątków Wyjątki nie zakłócą pracy programu W razie niespodziewanego błędu (np. braku pamięci) program może działać dalej Wszelkie zasoby zostają zwolnione mimo wyjątku Unikamy nie zwolnienia zasobów przez nieuwagę Zasoby są zwalniane automatycznie . Eclipse i OutOfMemoryException glBeginList i glEnd Krzysztof Czaiński
19
Bezpieczeństwo wyjątków a etap projektowania
template < typename T > class Stack { public: T pop(); // ... private: T* tab_; size_t size_; }; template < typename T > void Stack<T>::pop( T& result ) { // assert( size_ > 0 ); result = tab_[size_-1]; --size_; } template < typename T > T Stack<T>::pop() { // assert( size_ > 0 ); T result( tab_[size_-1] ); --size_; return result; } template < typename T > T Stack<T>::pop() { // assert( size_ > 0 ); return tab_[--size_]; } Krzysztof Czaiński
20
Podsumowanie Warto pisać kod w C++ uwzględniając wyjątki i warto uwzględnić to już na etapie projektowania. Dla zainteresowanych polecam: ZPR, dr inż. Robert Nowak 1. Nie jak dokumentacja, dopisywana później. Krzysztof Czaiński
Podobne prezentacje
© 2024 SlidePlayer.pl Inc.
All rights reserved.