Warsztat » Forum

[C++] Inteligentne wskaźniki

Jul 18, 2009 | Regedit |
22 wypowiedzi na 2 stronach:
1 2
Regedit
Jul 18, 2009

Inteligentne wskaźniki

Chciałbym rozpocząć dyskusję o inteligentnych wskaźnikach. Nie było tu jeszcze chyba takiej, a temat jest ważny. Mam właśnie zamiar napisać własne inteligentne wskaźniki i dlatego chciałem poprosić naszych "językoznawców" o radę :)

Jakie rodzaje inteligentnych wskaźników są przydatne? Dotychczas znałem te z STL i z Boost i używałem głównie scoped_ptr, czasem shared_ptr. Co z weak_ptr? Jakie mają zastosowanie? Czy zgadzacie się ze mną, że takie wskaźniki z przechodzącą własnością jakie ma STL w postaci auto_ptr to pomysłka i rzecz raczej nieprzydatna?

Jak radzicie najlepiej zaimplementować wskaźnik shared_ptr zliczający referencje? Czy przechowywać w każdym takim wskaźniku wskaźnik na właściwe dane oraz na licznik, czy też tak jak radzą niektórzy zarządzać jedną globalną mapą adresów skojarzonych z licznikami po to, żeby drugi inteligentny wskaźnik stworzony "od zera" z tego samego adresu poprawnie współpracował z pierwszym? Moim zdaniem to bardziej zaawansowane podejście nie ma większego sensu.

Czy inteligentny wskaźnik powinien mieć nie-explicit konstruktor dla typu T? Czy powinien mieć operator przypisania dla typu T zamiast jawnie wywoływanej metody reset? Czy powinien mieć konstruktor i operator przypisania jako metodę szablonową próbującą dokonać konwersji z inteligentnego wskaźnika pokazującego na inny typ T, tak jak ma auto_ptr? Czy powinien mieć operator * i -> zamiast zmuszać do jawnego wywoływania metody get? Jeśli nie, to dlaczego - jakie widzicie w tym niebezpieczeństwa???

Co sądzicie o moim pomyśle na parametryzowanie inteligentnych wskaźników klasą Policy mówiącą, jak zwalniać dany zasób? Chciałbym to napisać tak, żeby można było kombinować różne rodzaje wskaźników z różnymi policy, np.:

Kod: scoped_ptr< Klasa, DeletePolicy >
shared_ptr< int, DeleteArrayPolicy >
shared_ptr< IDirect3DTexture9, ReleasePolicy >


EDIT: Jeśli uznacie to za dobry pomysł, to jakie widzicie rozwiązanie kwestii niepodawania za każdym razem tego policy, skoro C++ nie ma czegoś takiego jak:
Kod: template <typename T> typedef scoped_ptr<T, DeletePolicy> deleting_scoped_ptr<T>;
Złośliwiec
Jul 19, 2009

Odp: Inteligentne wskaźniki

Krótko: nie używam. Uważam, że nawet najinteligentniejszy wskaźnik nie zastąpi inteligentnego programisty :).
Wiadomo
Jul 19, 2009

Odp: Inteligentne wskaźniki

Cytat:

Krótko: nie używam. Uważam, że nawet najinteligentniejszy wskaźnik nie zastąpi inteligentnego programisty :).
Zgadzam sie. Nigdy nie uzywalem, choc wiem w jaki sposob one pracuja. Ale tak jak Zlosliwiec uwazam, ze madry programista nie potrzebuje takich sztuczek i bez problemu poradzi sobie.
Regedit
Jul 19, 2009

Odp: Inteligentne wskaźniki

Dla niewierzących w potęgę inteligentnych wskaźników - one są konieczne kiedy używamy obsługi błędów na wyjątkach, bo inaczej w przypadku rzucenia wyjątku albo będzie wyciek pamięci, albo trzeba będzie pisać tak:

Kod: // BLEEEEEE!
int *Tablica = new int[10];
try
{
  // Robię coś, kto wie, może tu będzie wyjątek...
  delete [] Tablica;
}
catch (...)
{
  delete [] Tablica;
  throw;
}
Złośliwiec
Jul 20, 2009

Odp: Inteligentne wskaźniki

Cytat:

Dla niewierzących w potęgę inteligentnych wskaźników - one są konieczne kiedy używamy obsługi błędów na wyjątkach, bo inaczej w przypadku rzucenia wyjątku albo będzie wyciek pamięci, albo trzeba będzie pisać tak:


A czy wyciek w sytuacji wyjątkowej jest naprawdę aż tak wielkim problemem?
Koshmaar
Jul 21, 2009

Odp: Inteligentne wskaźniki

Gdyby nie boost::shared_ptr i boost::weak_ptr, w młodym wieku miałbym już pewnie pierwsze siwe włosy na głowie. Jakiś czas temu pisałem własny dosyć skomplikowany menadżer zasobów (jak zwykle w moim przypadku, bardzo wyrafinowany ;-) ) w który bylo sporo klas, powiązań, pełno przypisań, kopiowania obiektów przez wartość / referencje itp. Boost ocalił mnie przez debugowaniem tego cholerstwa, automagicznie zajmując się wszystkim, wliczając w to dziwne przypadkami graniczne.

Gdybym miał pisać to samemu, trwałoby to pewnie kilka tygodni dłużej, było wolniejsze, gorzej zaprojektowanie, używanie tego było męczarnią i kryło kilka złośliwych bugów które ujawnią się w przededniu premiery gry.


Reg: oczywiście wiesz, jaka będzie moja rada... daj spokój z pisaniem włansnych wersji, nie wyważaj otwartych drzwi, dalej używaj tego co działa (boost). Oczywiście wiem, że jeśli napisałeś ten temat to jesteś zdecydowany na zrobienie po swojemu i moje gadanie cię nie przekona.


Ostatnia sprawa... nie napisałeś czemu chcesz pisać własne wersje. Jeśli dla nauki to ok, mogę zrozumieć (choć IMHO są ciekawsze rzeczy do kodzenia).

[hr]

Złośliwiec: to zależy. Wyciek pamięci w sytuacji wyjątkowej, gdy cały program idzie do piachu, nie jest taki zły. Wyciek pamięci w sytuacji wyjątkowej, która może od czasu do czasu się zdarzyć (w końcu wyjątki nie są przypisane tylko do błędów), ale program po zareagowaniu ma poprawnie działać, jest już niemiły. A jeśli nie o samą pamięć idzie, lecz jakieś większe zasoby, to lepiej jednak uważać na to się dzieje w sytuacjach wyjątkowych.
bies
Jul 22, 2009

Odp: Inteligentne wskaźniki

Nie zgadzam się -- (const) auto_ptr jest w przydatny w pewnych zastosowaniach. Poza tym, ten przykład z tablicą to bzdura -- tu zamiast wskaźnika trzeba użyć klasy vector lub podobnej. A w ogóle to ,,C++ bardziej efektywny'' Meyersa i ,,Modern C++ design'' Alexandrescu -- tam jest dość sporo nt. inteligentnych wskaźników.
duzamasa
Jul 20, 2009

Odp: Inteligentne wskaźniki

Zgadzam sie z biesem.
Generalnie nie widze powodow, aby w normalnym kodzie korzystac z operatorow new i delete. Jesli cos takiego ma miejsce, to najczesciej tworze klase opakowujaca, ktora dba o zwalnianie oraz przydzielanie pamieci za pomoca new. Wydaje mi sie, ze klasy takie jak shared_ptr zliczajace obiekty do referencji powstaly nie po to, aby z nich korzystac przy kazdej okazji tylko do obslugi klas posiadajacych referencje do obiektow. Dzieki takiej referencji szybciej wykonuje sie operator przypisania oraz konstruktor kopiujacy, bo zwieksza sie tylko licznik odwolan.
O inteligentych wskaznikach poczytasz takze w ksiazce "C++ Szablony", o referencjach poczytasz w "Jezyk C++" Stroustrupa. Po przeczytaniu drugiej pozycji, sadze, ze stanie sie jasne, do czego mozna wykorzystac te "inteligentne wskazniki".
.
Jul 20, 2009

Odp: Inteligentne wskaźniki

Cytat:

Jakie rodzaje inteligentnych wskaźników są przydatne?
Jakie mają zastosowanie?
Jak radzicie najlepiej zaimplementować wskaźnik shared_ptr zliczający referencje?
Czy inteligentny wskaźnik powinien mieć nie-explicit konstruktor dla typu T?
Czy powinien mieć operator przypisania dla typu T zamiast jawnie wywoływanej metody reset?

Masz tu w prezencie od wujka kropeczki i Alexandrescu odpowiedzi na Twoje wszystkie pytania:
http://www.nowoczesne-cplusplus.com/pdfs/npwcpp-rozdz7.pdf


Jeśli sam zaimplementujesz różne techniki, nawet jeśli okażą się one mierne w porównaniu do tych TOP, to i tak dzięki zrozumieniu niektórych wewnętrznych mechanizmów, będziesz potrafił znacznie lepiej później operować na TOP’owych narzędziach. Nie słuchaj ludzi opowiadających o ponownym wymyślaniu koła, bo ponowne wymyślanie koła daje znacznie więcej aniżeli Im się wydaje…


Cytat:

Generalnie nie widze powodow, aby w normalnym kodzie korzystac z operatorow new i delete. Jesli cos takiego ma miejsce, to najczesciej tworze klase opakowujaca, ktora dba o zwalnianie oraz przydzielanie pamieci za pomoca new.

He he he, mój kumpel też nie widzi powodów… Ale On się leczy…
Złośliwiec
Jul 23, 2009

Odp: Inteligentne wskaźniki

Cytat:

Generalnie nie widze powodow, aby w normalnym kodzie korzystac z operatorow new i delete. Jesli cos takiego ma miejsce, to najczesciej tworze klase opakowujaca, ktora dba o zwalnianie oraz przydzielanie pamieci za pomoca new.


I zyskujesz tyle, że wreszcie nie musisz patrzeć na to ohydne new, prawda? :)
bies
Jul 24, 2009

Odp: Inteligentne wskaźniki

Cytat:

Cytat:

Generalnie nie widze powodow, aby w normalnym kodzie korzystac z operatorow new i delete. Jesli cos takiego ma miejsce, to najczesciej tworze klase opakowujaca, ktora dba o zwalnianie oraz przydzielanie pamieci za pomoca new.


I zyskujesz tyle, że wreszcie nie musisz patrzeć na to ohydne new, prawda? :)

Zyskujesz tyle, że nie musisz martwić się o wołanie delete (close(), disconnect(), release() itp.).
Moriturius
Jul 25, 2009

Odp: Inteligentne wskaźniki

Ee tam, ja mysle ze inteligentne wskazniki przydatne sa przy pisaniu wiekszych rzeczy bo pozwalaja sie skupiac na czym innym.

Co do rozmowy o delete i new to nie ma co gadac za wiele, generalnie sa 2 zasady wg mnie:

1) Kazdy robi jak chce
2) To co zastosuje zalezy od sytuacji
Regedit
Jul 26, 2009

Odp: Inteligentne wskaźniki

Jak zwykle okazuje się że pluralizm poglądów to frazes, istnieje tylko jedna słuszna droga rozwoju, a kto jej nie akceptuje ten jest lamer :) Zakładając, że ja jestem na tym etapie rozwoju, że już doceniam inteligentne wskaźniki, ale wciąż jeszcze wierzę, że warto je napisać samemu i to nie tylko dla celów edukacyjnych, zadam następne pytania:

Studiując książki Meyersa oraz dokumentację i źródła Boosta mam już jakiś pogląd jak powinny te moje wymarzone wskaźniki wyglądać. Dzięki za wasze odpowiedzi - poczytam dokładnie to co poleciliście dzisiaj jak wrócę z wykładów. Tymczasem dopytam o szczegóły tego co mnie zaintrygowało, mianowicie:

Cytat:
Zyskujesz tyle, że nie musisz martwić się o wołanie delete (close(), disconnect(), release() itp.).

Jak chcesz obudywać w inteligentne wskaźniki zasoby wymagające tak różnych sposobów niszczenia? Jak poradzisz sobie tu z problemem który opisałem na końcu mojej pierwszej wiadomości w tym wątku?

Wreszcie, jak potraficie całkiem wyeliminować wywołania new i delete??? Przecież nawet korzystając z inteligentnych wskaźników pisze się chyba w ten sposób:
Kod: class MojaKlasa {
private:
  scoped_ptr<Klasa2> m_Pole;
public:
  void UstawPole() { m_Pole.reset(new Klasa2()); }
  void WyczyscPole() { m_Pole.reset(); }
};
duzamasa
Jul 25, 2009

Odp: Inteligentne wskaźniki

Cytat:

Cytat:

Generalnie nie widze powodow, aby w normalnym kodzie korzystac z operatorow new i delete. Jesli cos takiego ma miejsce, to najczesciej tworze klase opakowujaca, ktora dba o zwalnianie oraz przydzielanie pamieci za pomoca new.

He he he, mój kumpel też nie widzi powodów… Ale On się leczy…


Tak jak napisalem: "w normalnym kodzie" czyli sterujacym programem, jego funkcjonalnoscia. Ale gdy jest to klasa w rodzaju z tych, które sa w bibliotece standardowej, to wowczas powinno sie korzystac z new i delete. Przynajmniej ja tak robie, zatem calkowicie o tych operatorach nie zapomnialem. Z tego powodu nie doradzam calkowitego usuniecia tych operatorow z C++  ;D
Jedna wada, ktora mnie drazni w bibliotece standardowej jest to, ze wszystkie obiekty w kolekcjach sa inicjowane. Zajmuje to czasami calkiem sporo czasu. Wtedy czasami korzystam z new i delete, aby zaoszczedzic troche czasu (niestety auto_ptr nie nadaje sie do tablic i dla mnie jest to pewna luka w standardzie, ze nie ma nic dla tablic, ktorych nie chce inicjalizowac w trakcie tworzenia obiektu).
Musze przyznac, ze zapomnialem o waznej rzeczy: dziedziczeniu i klasach bazowych. Tutaj nie da sie zastapic operatora new. I tutaj pewnie takze znajda zastosowanie "inteligentne wskazniki" (obok referencji).
bies
Jul 25, 2009

Odp: Inteligentne wskaźniki

Cytat:

Studiując książki Meyersa oraz dokumentację i źródła Boosta mam już jakiś pogląd jak powinny te moje wymarzone wskaźniki wyglądać. Dzięki za wasze odpowiedzi - poczytam dokładnie to co poleciliście dzisiaj jak wrócę z wykładów.

Jak już czytasz Boosta to pewnie możesz poczytać i Loki.

Cytat:

Cytat:
Zyskujesz tyle, że nie musisz martwić się o wołanie delete (close(), disconnect(), release() itp.).

Jak chcesz obudować w inteligentne wskaźniki zasoby wymagające tak różnych sposobów niszczenia? Jak poradzisz sobie tu z problemem który opisałem na końcu mojej pierwszej wiadomości w tym wątku?

Wyciąłeś z kontekstu (a forum umożliwia takie fajne cytowanie ;) ) -- tego typu zasoby zazwyczaj trzymane są nie przez inteligentne wskaźniki ale bardziej inteligentne klasy opakowujące (np. vector, socket, mutex, ifstream, database_connection itp.). Jeśli już chcesz ładować do wskaźników to potrzebujesz elastycznej strategii Deleter_Policy mającej dostęp do typu obiekty przechowywanego we wskaźniku. A template typedef będzie w C++0x (czyli pewnie najszybciej w gcc). Na razie po prostu musisz podawać albo wszystkie parametry szablonu albo żadnego (typedef ze zdefiniowanymi wszystkimi parametrami).

Cytat:

Wreszcie, jak potraficie całkiem wyeliminować wywołania new i delete???

Delete! New jest nieszkodliwe. To o delete można zapomnieć.

duzamasa: vector jest taką klasą do tablic.
Regedit
Jul 28, 2009

Odp: Inteligentne wskaźniki

bies: Dzięki za cenne informacje. Teraz już jest dla mnie wszystko jasne :)

Co do problemu z tymi Policy, to zrobię jednak osobne klasy scoped_ptr, scoped_arr_ptr, scoped_release_ptr, smart_ptr, smart_arr_ptr itd. :)
Strony:
1 2