Pakiet programów do zdalnego nauczania Programowania Orientowanego Obiektowo
Dzisiaj jest
Poniedziałek, 16 Lipiec 2018
Zarejestrowanych użytkowników: 4
Dostępnych pytań testowych: 102
HOME
Strona tytułowa pracy dyplomowej
NAUKA
Materiały dydaktyczne związane z OOP
TESTY
Sprawdzenie poziomu zdobytej wiedzy
ZASOBY
Literatura i zasoby sieciowe o OOP
ŹRÓDŁA
Zbiór projektów dydaktycznych z OOP
KONTO
Możliwość śledzenia własnych postępów
INFO



Czy prywatny konstruktor wystarczy?

Deklaracja wzorca projektowego Singleton zawiera prywatny konstruktor, który jest wywoływany wyłącznie raz za pomocą statycznej metody egzemplarz(). Czy rzeczywiście zapobiega to tworzeniu tylko jednej kopii egzemplarza klasy Generator? – niezupełnie.

Jeśli sięgnąć pamięcią do zasad generowania domyślnych elementów w klasach można zdać sobie sprawę iż:

  • jeśli nie zostanie zadeklarowany żaden konstruktor kompilator wygeneruje domyślny konstruktor bezargumentowy,
  • jeśli nie zostanie zadeklarowany konstruktor kopiujący kompilator wygeneruje domyślny konstruktor kopiujący,
  • jeśli nie zostanie zadeklarowany operator przypisania kompilator wygeneruje go automatycznie.

Okazuje się, że deklaracja singletonu przedstawiona w przykładzie 1 jest niewystarczająca, bowiem klient z łatwością może utworzyć drugi egzemplarz korzystając z domyślnie generowanego konstruktora kopiującego.

Generator * wsk = Generator::egzemplarz();
Generator * wsk2 = new Generator(*wsk);
std::clog << wsk->losuj(1.0) << std::endl;
std::clog << wsk2->losuj(1.0) << std::endl;

Konstruktor kopiujący dokonuje kopiowania płytkiego (kopiuje tablicę buforu i bieżące położenie następnego elementu). W wyniku powstanie drugie egzemplarz klasy Generator - kopia pierwszego. Dwie ostatnie linijki kodu dadzą w wyniku ten sam rezultat ponieważ zawartości bufora są takie same (ale nie jest to fizycznie ten sam bufor). O ile w przypadku klasy generatora nie zagraża to bezpieczeństwu, to w przypadku singletonów reprezentujących np. dostęp do urządzeń stanowiło by to poważny problem.

Aby zabezpieczyć się przed możliwością powyższego wywołania należy dodać deklaracje konstruktora kopiującego w sekcji prywatnej. Dzięki temu poniższe wywołanie spowoduje błąd kompilacji.

Generator * wsk2 = new Generator(*wsk);

Deklaracją prywatnego operatora przypisania nie należy się przejmować. Ponieważ nie ma możliwości stworzenia obiektu Generator na stosie (zapobiega temu konstruktor prywatny) to nie można w konsekwencji wywołać również operatora przypisania.

Adamik Łukasz, Politechnika Śląska w Gliwicach (AEiI) - 2010/11