Panel użytkownika
Nazwa użytkownika:
Hasło:
Nie masz jeszcze konta?

Jak organizować zarządzanie pamięcią w C++?

Ostatnio zmodyfikowano 2013-06-23 12:42
Autor Wiadomość
b00rt00s
Temat założony przez niniejszego użytkownika
Jak organizować zarządzanie pamięcią w C++?
» 2013-06-19 22:17:22
Witam, jest to mój pierwszy post na forum więc proszę o ewentualną wyrozumiałość, jeśli takie pytanie było już zadane.

Chciałbym również dodać, że jestem zupełnym samoukiem programowania: do tej pory uczyłem się głownie z książek i internetu, więc brak mi doświadczenia w pewnych kwestiach.

A teraz do rzeczy.

Pytanie jest z gatunku zagadnień projektowych. Kiedy korzystam z jakiejś biblioteki (np.: Qt), często zdarza mi się korzystać z klas i ich metod, które wymagają podania wskaźnika jako parametru lub zwracają wskaźnik. Zawsze mnie wtedy zastanawia: kto zarządza tym wskaźnikiem? Kto ma zwolnić pamięć po nim? Mój program, czy czy klasa która wymaga lub zwraca wskaźnik? Irytuje mnie dodatkowo fakt, że takich informacji nie ma w dokumentacji...

Zastanawiam się, jaką politykę należy przyjąć, kiedy sam piszę klasę? Na pewno są jakieś wzorce i dobre praktyki, które się stosuje w takich przypadkach. Chodzi mi o to, jak rozpoznać kto zarządza wskaźnikiem gdy korzystam z jakieś biblioteki, oraz jak pisać kod tak, aby inna osoba korzystająca z niego też nie miała wątpliwości co się dzieje.

Jak ktoś wie coś na ten temat, to prosiłbym o podzielenie się swoim doświadczeniem.
P-85840
m4tx
» 2013-06-20 06:22:11
Zawsze mnie wtedy zastanawia: kto zarządza tym wskaźnikiem? Kto ma zwolnić pamięć po nim? Mój program, czy czy klasa która wymaga lub zwraca wskaźnik?
W jaki sposób wyobrażasz sobie zwalnianie pamięci obiektu przez funkcję która ten wskaźnik zwraca? :) Przecież ona już jest zakończona, nie ma szans żeby Ci zwolniła pamięć - musisz to zrobić sam. To samo jest ze wskaźnikami przekazywanymi jako argument funkcji.
P-85847
Monika90
» 2013-06-20 08:36:36
Generalnie eksperci (patrz seria GotW Suttera, albo prezentacja Stroustrupa podczas ACCU 2013) odradzają użycie wskaźników typu wbudowanego (T*) w interfejsach. Między innymi dlatego, że nie jest jasne kto lub co zarządza czasem życia obiektu.

Dlatego aby nie było takich wątpliwości można:

1. Zwracać z funkcji przez wartość - to jest tanie dzięki optymalizacjom typu RVO oraz dzięki przenoszeniu (move-semantics) dla typów postaci handle-body jak np. std::vector<T>. Dzięki przenoszeniu jest to możliwe również dla typów, które są niekopiowalne (np. pliki czy wątki). Należy też zwracać std::optional<T> zamiast wskaźnika, który potencjalnie przyjmuje wartość NULL.

2. Jeśli to mozliwe to przekazywać do funkcji przez wartość - to jest dobre jeżeli obiekt jest mały, a zatem tani w kopiowaniu, albo gdy funkcja i tak musi utworzyć kopię. Daje też możliwość zastosowania przeniesienia gdy argumentem jest r-wartość.

3. Przekazywać przez referencję (być może const) - użytkownicy takich funkcji raczej nie będą oczekiwać, że te funkcje zniszczą obiekt.

4. Dla obiektów tworzonych na stercie używać inteligentnych wskaźników, takich jak:
 - std::unique_ptr<T>, który pozwala na przeniesienie odpowiedzialności za obiekt z jednej części programu do innej. Np. jeżeli funkcja przyjmuje argument typu unique_ptr<T>, to znaczy że przekazany obiekt należy wyłącznie do niej i ona zadba by był prawidłowo zniszczony gdy już nie będzie jej potrzebny. Podobnie, funkcje tworzące obiekty polimorficzne (fabryki) powinny zwracać unique_ptr (lub inny inteligenty wskaźnik).

 - std::shared_ptr<T> - gdy jest więcej niż jeden posiadacz obiektu, ale to raczej rzadko się zdarza.
P-85848
b00rt00s
Temat założony przez niniejszego użytkownika
» 2013-06-20 20:39:19
@m4tx:
W jaki sposób wyobrażasz sobie zwalnianie pamięci obiektu przez funkcję która ten wskaźnik zwraca? :)

W przypadku funkcji sprawa jest prosta. Ale co jeśli mamy do czynienia metodą? Skąd mam wiedzieć, czy metoda nie zwraca wskaźnika do obiektu składowego, którym zarządza obiekt na rzecz którego jest wykonywana ta metoda?

@Monika90

Wielkie dzięki, na takich informacjach mi zależało. Jednakże sprawa się komplikuje kiedy używasz biblioteki, która przyjmuje "surowe" wskaźniki. Tak mam np.: w przypadku korzystania z Qt. Często się to zdarza, że metoda jakiegoś obiektu wymaga podania wskaźnika lub zwraca wskaźnik. Staram się wtedy "na czuja" wywnioskować, co jest sensowne. Zawsze mam jednak wątpliwości.


[OT] Jak dodawać cytowania innych postów na tym forum, a jak kod, żeby miał podświetlenie składni? Nie mogę tego nigdzie znaleźć...

[cytat]...[/cytat] oraz ogólnie » KursyKurs STC kurs - xevuel
P-85873
DejaVu
» 2013-06-21 12:31:42
Staram się wtedy "na czuja" wywnioskować, co jest sensowne. Zawsze mam jednak wątpliwości.
Wówczas otwierasz dokumentację i czytasz jak działa dana klasa/funkcja/metoda :)
P-85906
akwes
» 2013-06-21 12:47:59
@DejaVu
Ale on mówił o sytuacji gdy:

Irytuje mnie dodatkowo fakt, że takich informacji nie ma w dokumentacji...

;)
P-85907
DejaVu
» 2013-06-21 12:55:47
Irytuje mnie dodatkowo fakt, że takich informacji nie ma w dokumentacji...
Wówczas zagląda się do kodu źródłowego używanej biblioteki :)
P-85909
akwes
» 2013-06-23 12:26:42
To też chyba nie jest dobre wyjście, raczej nie powinno się polegać na implementacji klasy bo ta może się zmieniać, a dodatkowo niszczy to abstrakcję kodu. Uzależnienie kodu od szczegółów implementacji klasy będzie niszczyło koncepcję programowania obiektowego, wprowadzało dodatkową zależność oraz zmuszało programistę do pamiętania o czymś więcej ;> Jeszcze gorzej jak gdzieś pojawi się pimpl idiom, wtedy trzeba szukać jeszcze głębiej ;>
P-85982
« 1 » 2
  Strona 1 z 2 Następna strona