Wręcz przeciwnie, zawsze powinieneś preferować alokacje stosu, do tego stopnia, że z reguły nigdy nie powinieneś mieć nowego / usuwania w kodzie użytkownika.
Jak powiedziałeś, kiedy zmienna jest zadeklarowana na stosie, jej destruktor jest wywoływany automatycznie, gdy wyjdzie poza zakres, co jest głównym narzędziem do śledzenia czasu życia zasobów i unikania wycieków.
Ogólnie rzecz biorąc, za każdym razem, gdy musisz przydzielić zasób, niezależnie od tego, czy jest to pamięć (przez wywołanie new), uchwyty plików, gniazda czy cokolwiek innego, opakuj go w klasę, w której konstruktor pozyskuje zasób, a destruktor zwalnia go. Następnie możesz utworzyć obiekt tego typu na stosie i masz gwarancję, że Twój zasób zostanie zwolniony, gdy wyjdzie poza zakres. W ten sposób nie musisz wszędzie śledzić nowych / usuwanych par, aby uniknąć wycieków pamięci.
Najpopularniejszą nazwą tego idiomu jest RAII
Przyjrzyj się także klasom inteligentnych wskaźników, które są używane do zawijania wynikowych wskaźników w rzadkich przypadkach, gdy musisz przydzielić coś nowym poza dedykowanym obiektem RAII. Zamiast tego przekazujesz wskaźnik do inteligentnego wskaźnika, który następnie śledzi jego czas życia, na przykład przez zliczanie odwołań, i wywołuje destruktor, gdy ostatnie odwołanie wykracza poza zakres. Biblioteka standardowa std::unique_ptr
umożliwia proste zarządzanie w oparciu o zakres i std::shared_ptr
zliczanie odniesień w celu wdrożenia współwłasności.
Wiele samouczków demonstruje tworzenie instancji obiektu za pomocą fragmentu kodu, takiego jak ...
Odkryłeś więc, że większość samouczków jest do niczego. ;) Większość samouczków uczy cię kiepskich praktyk C ++, w tym wywoływania new / delete w celu tworzenia zmiennych, gdy nie jest to konieczne, i utrudnia śledzenie czasu życia przydziałów.
Chociaż posiadanie rzeczy na stosie może być zaletą pod względem alokacji i automatycznego zwalniania, ma pewne wady.
Możesz nie chcieć przydzielać dużych obiektów na stosie.
Dynamiczna wysyłka! Rozważ ten kod:
Spowoduje to wydrukowanie „B”. Zobaczmy teraz, co się dzieje podczas używania stosu:
Spowoduje to wydrukowanie „A”, co może nie być intuicyjne dla osób znających Javę lub inne języki obiektowe. Powodem jest to, że nie masz już wskaźnika do instancji
B
. Zamiast tegoB
tworzona jest instancja programu i kopiowana doa
zmiennej typuA
.Niektóre rzeczy mogą się wydarzyć nieintuicyjnie, zwłaszcza gdy jesteś nowicjuszem w C ++. W C masz swoje wskaźniki i to wszystko. Wiesz, jak ich używać i ZAWSZE robią to samo. W C ++ tak nie jest. Wystarczy wyobrazić sobie, co się dzieje, gdy używasz w tym przykładzie jako argument do metody - robi się bardziej skomplikowane i to robi ogromną różnicę, jeżeli
a
jest typuA
lubA*
nawetA&
(call-by-reference). Możliwych jest wiele kombinacji i wszystkie zachowują się inaczej.źródło
Cóż, powód użycia wskaźnika byłby dokładnie taki sam, jak powód użycia wskaźników w C przydzielonych za pomocą malloc: jeśli chcesz, aby twój obiekt żył dłużej niż zmienna!
Jest nawet wysoce zalecane, aby NIE używać nowego operatora, jeśli możesz tego uniknąć. Zwłaszcza jeśli używasz wyjątków. Generalnie znacznie bezpieczniej jest pozwolić kompilatorowi zwolnić obiekty.
źródło
Widziałem ten anty-wzorzec od ludzi, którzy nie do końca rozumieją operator & address-of. Jeśli potrzebują wywołać funkcję ze wskaźnikiem, zawsze alokują na stercie, aby uzyskać wskaźnik.
źródło
Traktuj stertę jako bardzo ważną nieruchomość i używaj jej bardzo rozsądnie. Podstawową zasadą kciuka jest używanie stosu, gdy tylko jest to możliwe, i sterty, gdy nie ma innego wyjścia. Alokując obiekty na stosie, możesz uzyskać wiele korzyści, takich jak:
(1). Nie musisz martwić się o rozwijanie stosu w przypadku wyjątków
(2). Nie musisz martwić się fragmentacją pamięci spowodowaną przydzieleniem większej ilości miejsca niż jest to konieczne przez menedżera sterty.
źródło
Jedynym powodem, dla którego bym się martwił, jest to, że Pies jest teraz przydzielony na stosie, a nie na stosie. Jeśli więc pies ma rozmiar megabajtów, możesz mieć problem,
Jeśli musisz przejść nową / usunąć trasę, uważaj na wyjątki. Z tego powodu powinieneś używać auto_ptr lub jednego z typów inteligentnych wskaźników doładowania, aby zarządzać czasem życia obiektu.
źródło
Nie ma powodu do nowego (na stercie), kiedy możesz alokować na stosie (chyba że z jakiegoś powodu masz mały stos i chcesz go użyć.
Możesz rozważyć użycie shared_ptr (lub jednego z jego wariantów) z biblioteki standardowej, jeśli chcesz alokować na stercie. To zajmie się usunięciem za Ciebie, gdy wszystkie odniesienia do shared_ptr znikną.
źródło
Istnieje dodatkowy powód, o którym nikt inny nie wspomniał, dla którego możesz zdecydować się na dynamiczne tworzenie obiektu. Dynamiczne obiekty oparte na stercie pozwalają na wykorzystanie polimorfizmu .
źródło
Miałem ten sam problem w Visual Studio. Musisz użyć:
yourClass-> classMethod ();
zamiast:
yourClass.classMethod ();
źródło