Wykład 7 - sprytne wskaźniki. 20 kwietnia 2007
Potrzeba współdzielenia kodu źródłowego Pojęcia niezależne od typu: kolekcje (np. listy) algorytmy (np. znajdowania największego elementu) Szablony mechanizm czasu kompilacji kod nie jest kompilowany, jeżeli nie został użyty
Problem typu Typowy problem - jawne wskazanie, że identyfikator jest typem class Foo { public: typedef int Element; /* dalsza część implementacji klasy Foo */ }; template<typename T> void f(const T& t) { //Poniżej błędnie zakłada, że T::Element to nazwa składowej T::Element e = 0; //... //Poniżej jawnie wskazano, że T::Element to nazwa typu typename T::Element e = 0; //... };
boost::scoped_ptr Odpowiada strategii zdobywanie zasobów jest inicjowaniem Destruktor usuwa wskaźnik Zabronione kopiowanie template<typename T> class scoped_ptr : noncopyable { public: explicit scoped_ptr(t* p = 0) : p_(p) {} scoped_ptr(){ delete p_; } //Usuwa obiekt wskazywany T& operator*() { return *p_; } T* operator->() { return p_; } private: T* p_; //Wskaźnik, którym zarządza }; void f() { scoped_ptr<mojaklasa> klasa(new MojaKlasa); //kod, który może wyrzucać wyjątki } //Destruktor klasy scoped_ptr wywoła operator delete
Wzorzec pimpl - ukrywanie implementacji class Foo { public: //Interfejs klasy private: //Implementacja jest ukryta struct Impl;//Deklaracja poprzedzająca scoped_ptr<impl> pimpl_;//sprytny wskaźnik }; zalety wady
std::auto_ptr - kopiowanie jest przekazywaniem własności Odpowiada strategii zdobywanie zasobów jest inicjowaniem Destruktor usuwa wskaźnik Dozwolone kopiowanie (!) - przenosi ono uprawnienia template<typename T> class auto_ptr { public: explicit auto_ptr(t* p = 0) : p_(p) {} //nie jest const auto_ptr&! auto_ptr(auto_ptr& a) p_(a.p_) { a.p_ = 0L; } auto_ptr& operator=(auto_ptr& a); //nie jest const auto_ptr& auto_ptr() { delete p_; } //usuwa obiekt wskazywany T& operator*() { return *p_; } T* operator->() const { return p_; } private: T* p_; };
std::auto_ptr - przykłady #include <memory> using namespace std; class Foo { /* implementacja */ }; //funkcja zwraca wskaźnik na obiekt auto_ptr<foo> createfoo(int n) { return auto_ptr<foo>(new Foo(n) ); } { auto_ptr<foo> p(new Foo(1) ); /* tutaj wykorzystuje obiekt klasy */ }//automatycznie wolany destruktor createfoo(2); //nie wykorzystana wartość zwracana zostanie usunięta { auto_ptr<foo> v = createfoo(3); /* wykorzystanie obiektu v */ }//destruktor zwalnia zasob
std::auto_ptr niebezpieczeństwa #include <memory> using namespace std; class Foo { /* implementacja */ }; //Niebezpieczne! użycie auto_ptr jako argumentu void read(auto_ptr<foo> p) { /* wykorzystuje */ } { auto_ptr<foo> x = createfoo(4); read(x); //teraz x nie wskazuje na nic! } //Niebezpieczne! użycie auto_ptr w kolekcji vector<auto_ptr<foo> > v;
boost::shared_ptr - sprytny wskaźnik shared_ptr counter object konstruktor : tworzy licznik i inicjuje go na 1 konstruktor kopiujący: zwiększa licznik odniesień destruktor: zmniejsza licznik odniesień, jeżeli ma on wartość 0 to kasuje obiekt
sprytny wskaźnik - przykład p1 counter 1 #include <boost/shared_ptr.hpp> using namespace boost; class Foo { /* implementacja */ }; { shared_ptr<foo> p1(new Foo(1) ); { shared_ptr<foo> p2(p1); //licznik odniesien == 2 /*... */ } //destruktor p2, licznik = 1 } //destruktor p1 usuwa obiekt p1 p2 p1 object counter 2 object counter object 1
sprytny wskaźnik - przykład 2 #include <boost/shared_ptr.hpp> using namespace boost; class Foo { /* implementacja */ }; //funkcja zwraca wskaźnik na obiekt shared_ptr<foo> createfoo(int n) { return shared_ptr<foo>(new Foo(n) ); } { shared_ptr<foo> p2 = createfoo(2); }//destruktor zwalnia zasob p1 p1 p2 p2 counter 1 object counter 2 object counter object 1
Sprytny wskaźnik boost::shared_ptr zalety wady
- podsumowanie std::auto_ptr boost::shared_ptr boost::weak_ptr boost::intrusive_ptr
wstęp Zasady extreme programming podsumowanie Model wodospadowy Wodospadowy ( tradycyjny ) model tworzenia oprogramowania: 1. analiza, 2. projektowanie, Koszt 3. implementacja, 4. testowanie, 5. wdrożenie, 6. pielęgnacja. Wady: duże ryzyko niepowodzenia projektu, długi czas sprzężenia zwrotnego. Przyczyny: Czas wykładniczy (względem czasu) wzrost kosztów zmian w projekcie.
wstęp Zasady extreme programming podsumowanie Extreme programming Możliwości uzyskania innej krzywej kosztu zmian w czasie: prostota projektu, automatyczne testy, nastawienie na ciągłe zmiany w projekcie, polepszenie komunikacji. Właściwości: krótki czas sprzężenia zwrotnego, Koszt mniejsze ryzyko niepowodzenia projektu. Czas
wstęp Zasady extreme programming podsumowanie Zmniejszenie ryzyka niepowodzenia projektu dobrze sprecyzowany cel projektu, krótkie wersje, planowanie krótkofalowe, ciągła weryfikacja założeń.
wstęp Zasady extreme programming podsumowanie Zmniejszenie kosztów zmian Utrzymywanie działającej wersji przez cały czas: automatyczne testowanie: modułów, funkcjonalne. ciągła integracja. Utrzymywanie kodów źródłowych dobrej jakości zmiana struktury programu bez zmiany funkcjonalności (refactoring) przegląd kodu. Poprawa komunikacji: kolektywne prawo do zmian kodu, stosowanie narzędzi zarządzających wersjami.
wstęp Zasady extreme programming podsumowanie Sterowanie projektem koszt, czas, jakość, zakres.
wstęp Zasady extreme programming podsumowanie Podsumowanie Zasady XP: krótkie cykle oprogramowania, nieustanne testowanie, natychmiastowa integracja, brak szczegółowego projektu, brak szczegółowego planu.