Warsztat - Programowanie gier

Lipiec 30, 2010, 17:33:02 *
Witamy, Gość. Zaloguj się, lub zarejestruj proszę.

Zaloguj się podając nazwę użytkownika, hasło i długość sesji
Aktualności: Warsztat, Regulamin forum, #warsztat, Wiki, FAQ, NoPaste, Mapa
 
   Strona główna   Pomoc Szukaj Zaloguj się Rejestracja  
Strony: [1]
  Drukuj  
Autor Wątek: Pimpl - za i przeciw  (Przeczytany 1970 razy)
Kos
Member2000
*******

wiadomości: 3383



Zobacz profil
« : Sierpień 07, 2008, 18:06:20 »

Zastanawiam się, czy zacząć używać wzorca PImpl (Pointer to implementation) jako swojego "nowego standardu". Rozważam jakie konsekwencje to za sobą pociągnie - warto, nie warto? Na chwilę obecną przychodzą mi do głowy:

+ W nagłówkach jest to, co faktycznie 'na chłopski rozum' powinno być w nagłówkach - w kodzie jest jakby większy porządek.
+ Oszczędzamy (zapewne sporo) na czasie kompilacji - dużo mniejsze łańcuszki includów, mniejszy mętlik, brak potrzeby przebudowania połowy projektu przy dodaniu jednej składowej prywatnej.

- Drobne niewygody typu operator= (nieduży problem, można sporo z tego typu bananów dodać sobie w IDE do szablonu nowej klasy)
- Nieco mętliku przy dodawaniu parametryzowanych konstruktorów, bo chyba trzeba je ręcznie dopisywać w 2 miejscach
- Nieco więcej mętliku przy prostych getterach/setterach. Mam zwyczaj wpisywania ich kodu bezpośrednio w definicji klasy, będzie trzeba zmienić nawyk.
Co ważniejsze - zastanawiam się czy przy PImpl da się w ogóle zrealizować takie funkcje jako inline? Nie jestem tutaj pewien, ale wydaje mi się że by zaszło inlinowanie, inne moduły muszą znać treść tych funkcji, więc i tak musiałaby ona być w headerze, nie w .cpp z implementacją. Chyba że inlinowanie następuje dopiero podczas linkowania? Jak to jest?

Chętnie też posłucham, co Wy uważacie na temat używanie tego rozwiązania na co dzień. Opłaca się na tyle, by robić sobie z tego standard? (Oczywiście nie mam tu na myśli maniakalnego "pimplowania" każdej możliwej klasy - z rozwagą, z rozwagą).
Zapisane

Eclipse!
yarpen
SuperHero Member
******

wiadomości: 1423


Zobacz profil WWW
« Odpowiedz #1 : Sierpień 07, 2008, 18:27:32 »

Nie da sie w prosty sposob inline'owac f-kcji.
Problem z kopiowaniem jest dla mnie wydumany, bo jezeli obiekty maja podlegac kopiowaniu, to najczesciej klasa jest tak mala, ze nie ma sensu tam wsadzac pimpla.
Bonusowym klopotem jest dodatkowa allokacja (da sie tego uniknac, ale nie jest to za ladne).
Zapisane
bies
Gość
« Odpowiedz #2 : Sierpień 07, 2008, 18:29:40 »

Tak, linker może rozwinąć takie funkcje. Poza tym może to zrobić kompilator w trybie optymalizacji całego programu (WPO albo sztuczka z sqlite).

Co do Pimpla: tam gdzie warto, warto. Wink
« Ostatnia zmiana: Sierpień 07, 2008, 18:32:40 wysłane przez bies » Zapisane
Reg
Member2000
*******

wiadomości: 3791



Zobacz profil WWW
« Odpowiedz #3 : Sierpień 07, 2008, 22:27:56 »

Ja jestem podobnego zdania co bies i yarpen. Stosuję pimpl czasami - do dużych i rozbudowanych klas. Takie klasy nie mają kilku konstruktorów przyjmujących różne zestawy parametrów, nie mają zbyt wielu getterów i setterów do pojedynczych wartości, nie mają operatora przypisania ani innych takich składników, typowych dla małych klas "konkretnych" takich jak wektor, macierz.

Mają za to bardzo rozbudowaną implementację, która nierzadko wymaga długiej listy prywatnych pól, metod, struktur, enumów, a także znajomości definicji z dodatkowych bibliotek. Takie pola, metody i inne składniki trzeba byłoby definiować w nagłówku, a także włączyć w nim nagłówek używanej tylko do prywatnych celów biblioteki zewnętrznej (np. DirectX, FMOD), choćby po to żeby znane były zdefiniowane w nim typy. To powoduje, że kompilacja trwa długo i że wiele plików projektu musi zostać przekompilowane przy każdej zmianie w prywatnych szczegółach takiej klasy. A to wkurza i właśnie dlatego pimpl warto używać. Fajnie byłoby gdyby to nie było potrzebne, no ale C++ to C++...
Zapisane

Firkraag
Newbie
*

wiadomości: 34


Zobacz profil
« Odpowiedz #4 : Wrzesień 28, 2008, 17:50:39 »

Można też rozważyć użycie klas interfejsowych (w C++ tych ze wszystkimi metodami czysto wirtualnymi) a całą implementację wrzucić do pliku .cpp do klasy dziedziczącej po tej w pliku nagłówkowym. I dodac jakąś statyczną funkcję fabrykującą.
Coś w stylu:
Kod:
//foo.hpp
#include <memory>

struct Foo {
 typedef std::auto_ptr<Foo> Ptr_t;

 ~virtual Foo() = 0;
 virtual void set(int x) = 0;
 virtual void print() const = 0;

 static Ptr_t create(); // statyczna metoda fabrykująca
};

// foo.cpp
include "foo.hpp"
#include <iostream>
using std::cout;

Foo::~Foo() {}

struct Foo_impl : Foo {
 Foo_impl() : m_x(0) {}
 virtual void set(int x) { m_x = x; }
 virtual void print() const { cout << m_x << '\n'; }

 int m_x;   
};

void Foo::create()
{
 return Ptr_t(new Foo_impl());
}

//main.cpp
#include "foo.hpp"

int main()
{
 Foo::Ptr_t ptr(Foo::create());
 ptr->print();
 ptr->set(42);
 ptr->print();
}
Fakt, że wtedy mamy do czynienia z jakimś tam wskaźnikiem a nie obiektem.
« Ostatnia zmiana: Wrzesień 28, 2008, 18:09:18 wysłane przez Firkraag » Zapisane
Reg
Member2000
*******

wiadomości: 3791



Zobacz profil WWW
« Odpowiedz #5 : Wrzesień 28, 2008, 21:30:18 »

To bywa fajne rozwiązanie, szczególnie jeśli mogą powstawiać obiekty różnych typów i użytkownik ma nie być tego świadomy. Mój ulubiony przykład to VFS: funkcja montująca wskazaną lokalizację albo otwiera plik archiwum VFS, albo zwykły katalog na dysku i zwraca wskaźnik do wspólnego interfejsu.

Problem jest tu jednak taki, że metody 1. nie są inline 2. są wirtualne, a z tego wynika wolne działanie. To jest OK jeśli te metody są wywoływane rzadko i robią duże rzeczy, na przykład realizują we/wy do plików. Ale jeśliby to miały być jakieś gettery/settery, to już trochę lipa :/
Zapisane

Strony: [1]
  Drukuj  
 
Skocz do:  

Hosting: Polska Strefa - Ogłoszenia
Powered by SMF 1.1.7 | SMF © 2006, Simple Machines LLC