Dlaczego programiści C++ powinni minimalizować użycie 'nowego'?

Natknąłem się na przepełnienie stosu pytanie wyciek pamięci przy użyciu STD::list<:string> i jeden z komentarzy mówi tak:

Przestań tyle używać new. Nie widzę żadnego powodu, dla którego używałeś nowego nigdzie. ty. Można tworzyć obiekty według wartości w C++ i jest to jeden z ogromne korzyści z używania języka.
Nie musisz przydzielać wszystko na stercie.
Przestań myśleć jak programista Java .

Nie jestem pewien, o co mu chodzi.

Dlaczego obiekty powinny być tworzone przez wartość w C++ tak często, jak to możliwe, i jaka to różnica wewnątrz?
Źle zinterpretowałem odpowiedź?

Author: Arsen Khachaturyan, 2011-06-28

18 answers

Istnieją dwie powszechnie stosowane techniki alokacji pamięci: automatyczna alokacja i dynamiczna alokacja. Zwykle dla każdego z nich istnieje odpowiedni region pamięci: stos i sterta.

Stos

Stos zawsze przydziela pamięć w sekwencyjny sposób. Może to zrobić, ponieważ wymaga zwolnienia pamięci w odwrotnej kolejności(First-In, Last-Out: FILO). Jest to technika alokacji pamięci dla zmiennych lokalnych w wielu językach programowania. Jest bardzo, bardzo szybko, ponieważ wymaga minimalnej księgowości, a następny adres do przydzielenia jest niejawny.

W C++ nazywa się to automatic storage , ponieważ magazyn jest żądany automatycznie na końcu zakresu. Po zakończeniu wykonywania bieżącego bloku kodu (rozdzielanego za pomocą {}), pamięć dla wszystkich zmiennych w tym bloku jest automatycznie pobierana. Jest to również moment, w którym destruktory są wywoływane do czyszczenia zasobów.

Kupa

The heap pozwala na bardziej elastyczny tryb alokacji pamięci. Księgowość jest bardziej złożona, a przydział jest wolniejszy. Ponieważ nie ma implicit release point, musisz zwolnić pamięć ręcznie, używając delete lub delete[] (free W C). Jednak brak ukrytego punktu uwalniania jest kluczem do elastyczności sterty.

Powody korzystania z dynamicznej alokacji

Nawet jeśli używanie sterty jest wolniejsze i potencjalnie prowadzi do wycieków pamięci lub fragmentacji pamięci, są doskonale przypadki użycia dla dynamicznej alokacji, ponieważ jest ona mniej ograniczona.

Dwa główne powody, dla których należy używać alokacji dynamicznej:

  • Nie wiesz, ile pamięci potrzebujesz w czasie kompilacji. Na przykład, podczas czytania pliku tekstowego w ciąg znaków, zwykle nie wiesz, jaki rozmiar ma Plik, więc nie możesz zdecydować, ile pamięci przeznaczyć, dopóki nie uruchomisz programu.

  • Chcesz przydzielić pamięć, która będzie trwała po opuszczeniu bieżącego bloku. Na przykład, ty może chcieć napisać funkcję string readfile(string path), która zwraca zawartość pliku. W takim przypadku, nawet jeśli stos może pomieścić całą zawartość pliku, nie można powrócić z funkcji i zachować przydzielonego bloku pamięci.

Dlaczego dynamiczna alokacja jest często niepotrzebna

W C++ istnieje zgrabna konstrukcja o nazwie Destruktor . Mechanizm ten pozwala na zarządzanie zasobami poprzez dostosowanie czasu życia zasobu do czasu życia zmiennej. To technika nazywa się RAII i jest punktem wyróżniającym C++. "Zawija" zasoby w obiekty. To doskonały przykład. Ten fragment:

int main ( int argc, char* argv[] )
{
    std::string program(argv[0]);
}

Faktycznie przydziela zmienną ilość pamięci. Obiekt std::string przydziela pamięć za pomocą sterty i zwalnia ją w destruktorze. W tym przypadku nie trzeba ręcznie zarządzać dowolnymi zasobami i nadal ma zalety dynamicznej alokacji pamięci.

W szczególności oznacza to, że w tym fragment:

int main ( int argc, char* argv[] )
{
    std::string * program = new std::string(argv[0]);  // Bad!
    delete program;
}

Istnieje niepotrzebna dynamiczna alokacja pamięci. Program wymaga więcej wpisywania (!) i wprowadza ryzyko zapomnienia o dealokacji pamięci. Robi to bez widocznych korzyści.

Dlaczego należy używać automatycznego przechowywania tak często, jak to możliwe

W zasadzie ostatni akapit podsumowuje to. Korzystanie z automatycznego przechowywania tak często, jak to możliwe sprawia, że programy:

  • faster to type;
  • faster when run;
  • mniej podatne na wycieki pamięci / zasobów.

Punkty bonusowe

W zadanym pytaniu pojawiają się dodatkowe obawy. W szczególności, następująca Klasa:

class Line {
public:
    Line();
    ~Line();
    std::string* mString;
};

Line::Line() {
    mString = new std::string("foo_bar");
}

Line::~Line() {
    delete mString;
}

Jest w rzeczywistości o wiele bardziej ryzykowne w użyciu niż następujące:

class Line {
public:
    Line();
    std::string mString;
};

Line::Line() {
    mString = "foo_bar";
    // note: there is a cleaner way to write this.
}

Powodem jest to, że std::string poprawnie definiuje Konstruktor kopiujący. Rozważmy następujący program:

int main ()
{
    Line l1;
    Line l2 = l1;
}

Używając oryginalnej wersji, ten program prawdopodobnie ulegnie awarii, ponieważ używa delete na tym samym łańcuchu dwukrotnie. Korzystanie ze zmodyfikowanego wersja, każda instancja Line będzie miała swój własny łańcuch instancja, każda z własną pamięcią i obie zostaną wydane na końcu programu.

Inne uwagi

Szerokie użycieRAII {[59] } jest uważane za najlepszą praktykę w C++ ze wszystkich powyższych powodów. Istnieje jednak dodatkowa korzyść, która nie jest natychmiast oczywista. Zasadniczo jest to lepsze niż suma jego części. Cały mechanizm składa się . Skaluje się.

Jeśli używasz Klasa Line jako budulec:

 class Table
 {
      Line borders[4];
 };

Then

 int main ()
 {
     Table table;
 }

Przydziela cztery instancje std::string, cztery instancje Line, jedną instancję Table i całą zawartość łańcucha oraz Wszystko jest automatycznie uwalniane .

 1072
Author: André Caron,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-06-20 09:12:55

Ponieważ stos jest szybszy i szczelny

W C++, potrzeba tylko jednej instrukcji, aby przydzielić miejsce -- na stosie -- dla każdego obiektu Local scope w danej funkcji, i nie jest możliwe wycieknięcie żadnej z tej pamięci. Ten komentarz zamierzał (lub powinien był zamierzać) powiedzieć coś w stylu "Użyj stosu, a nie stosu".

 175
Author: DigitalRoss,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-07-28 20:37:30

Powód jest skomplikowany.

Po pierwsze, C++ nie jest zbieraniem śmieci. Dlatego dla każdej nowej musi być odpowiednie usunięcie. Jeśli nie umieścisz tego Usuń w, to masz wyciek pamięci. W takim prostym przypadku:

std::string *someString = new std::string(...);
//Do stuff
delete someString;
To proste. Ale co się stanie, jeśli "robić rzeczy" rzuci wyjątek? UPS: wyciek pamięci. Co się stanie, jeśli problemy" zrób coś " return wcześnie? UPS: wyciek pamięci.

A to dla najprostszego przypadku . W przypadku wystąpienia aby komuś zwrócić ten ciąg, teraz musi go usunąć. A jeśli podadzą to jako argument, czy osoba odbierająca musi to usunąć? Kiedy powinni go usunąć?

Lub, możesz po prostu zrobić to:

std::string someString(...);
//Do stuff

Nie delete. Obiekt został utworzony na "stosie" i zostanie zniszczony, gdy wyjdzie poza zasięg. Można nawet zwrócić obiekt, przenosząc w ten sposób jego zawartość do funkcji wywołującej. Można przekazać obiekt do funkcji (zazwyczaj jako referencję lub const-reference: void SomeFunc(std::string &iCanModifyThis, const std::string &iCantModifyThis). I tak dalej.

Wszystkie Bez new i delete. Nie ma wątpliwości, kto jest właścicielem pamięci lub kto jest odpowiedzialny za jej usunięcie. Jeśli tak:

std::string someString(...);
std::string otherString;
otherString = someString;

Zrozumiałe jest, że otherString posiada kopię danych z someString. Nie jest to wskaźnik, jest to osobny obiekt. Mogą mieć taką samą zawartość, ale możesz zmienić jedną bez wpływu na drugą:

someString += "More text.";
if(otherString == someString) { /*Will never get here */ }

Widzisz pomysł?

 111
Author: Nicol Bolas,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-07-29 00:43:11

Obiekty utworzone przez {[0] } muszą być ostatecznie deleted, aby nie wyciekły. Destruktor nie zostanie wywołany, pamięć nie zostanie uwolniona, cały bit. Ponieważ C++ nie ma zbierania śmieci, jest to problem.

Obiekty utworzone przez wartość (np. na stosie) automatycznie umierają, gdy wychodzą poza zakres. Wywołanie destruktora jest wstawiane przez kompilator, a pamięć jest automatycznie zwalniana po powrocie funkcji.

Inteligentne Wskaźniki jak unique_ptr, shared_ptr rozwiązać problem zwisającego odniesienia, ale wymagają dyscypliny kodowania i mają inne potencjalne problemy (kopiowalność, pętle odniesienia itp.).

Również, w scenariuszach wielowątkowych, new jest punktem spornym między wątkami; może mieć wpływ na wydajność nadużywania new. Tworzenie obiektów stosu jest z definicji thread-local, ponieważ każdy wątek ma swój własny stos.

Minusem obiektów value jest to, że umierają one po powrocie funkcji hosta - nie można przekazać referencji do tych z powrotem do wywołującego, tylko kopiując, zwracanie lub przesuwanie według wartości.

 77
Author: Seva Alekseyev,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-06-19 20:18:31
  • C++ nie używa własnego menedżera pamięci. Inne języki, takie jak C#, Java ma garbage collector do obsługi pamięci
  • implementacje C++ zazwyczaj wykorzystują procedury systemu operacyjnego do przydzielania pamięci i zbyt wiele nowych / usuniętych może fragmentować dostępną pamięć
  • w przypadku dowolnej aplikacji, Jeśli pamięć jest często używana, zaleca się wstępnie przydzielenie jej i zwolnienie, gdy nie jest to wymagane.
  • niewłaściwe zarządzanie pamięcią może prowadzić do wycieków pamięci i to ciężko namierzyć. Tak więc używanie obiektów stosu w zakresie funkcji jest sprawdzoną techniką
  • minusem używania obiektów stosu jest to, że tworzy wiele kopii obiektów po powrocie, przejściu do funkcji itp. Jednak inteligentne Kompilatory są dobrze świadome tych sytuacji i zostały dobrze zoptymalizowane pod kątem wydajności
  • to jest naprawdę uciążliwe w C++, jeśli pamięć jest przydzielana i zwalniana w dwóch różnych miejscach. Odpowiedzialność za uwolnienie jest zawsze pytaniem i bazujemy głównie na powszechnie dostępnych wskaźnikach, obiektach stosu (maksymalnie możliwe) i technikach takich jak auto_ptr (obiekty RAII)
  • najlepsze jest to, że masz kontrolę nad pamięcią, a najgorsze jest to, że nie będziesz miał żadnej kontroli nad pamięcią, jeśli zastosujemy niewłaściwe zarządzanie pamięcią dla aplikacji. Awarie spowodowane uszkodzeniem pamięci są najbardziej paskudne i trudne do wyśledzenia.
 32
Author: sarat,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-07-28 20:41:16

Widzę, że brakuje kilku ważnych powodów, aby zrobić jak najmniej nowych:

Operator new mA niedeterministyczny czas wykonania

Wywołanie new może, ale nie musi, spowodować, że system operacyjny przydzieli nową fizyczną stronę do twojego procesu. Albo może już mieć gotowe Miejsce Pamięci, nie wiemy. Jeśli twój program musi mieć spójny i przewidywalny czas wykonania (np. w systemie czasu rzeczywistego lub symulacji gry / fizyki) musisz unikać new w pętlach krytycznych czasu.

Operator {[0] } jest ukrytą synchronizacją wątków

Tak, słyszałeś, Twój system operacyjny musi upewnić się, że tabele stron są spójne i jako takie wywołanie new spowoduje, że Twój wątek uzyska ukrytą blokadę mutex. Jeśli konsekwentnie wywołujesz new z wielu wątków, faktycznie serializujesz swoje wątki (zrobiłem to z 32 procesorami, każdy uderzając w new, aby uzyskać kilkaset bajtów każdy, AUĆ! to było Królewskie p. I.t. A. to debug)

Pozostałe, takie jak powolne, fragmentacja, podatne na błędy itp., zostały już wymienione przez inne odpowiedzi.

 23
Author: Emily L.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-02-12 17:57:02

Pre-C++17:

Ponieważ jest podatny na subtelne wycieki , nawet jeśli zawijasz wynik w inteligentny wskaźnik .

Rozważ "uważnego" użytkownika, który pamięta o zawijaniu obiektów w inteligentne wskaźniki:

foo(shared_ptr<T1>(new T1()), shared_ptr<T2>(new T2()));

Ten kod jest niebezpieczny, ponieważ nie ma żadnej gwarancji, że shared_ptr jest skonstruowany przed albo T1 lub T2. Dlatego, jeśli jeden z new T1() lub new T2() zawiedzie po sukcesie drugiego, to pierwszy obiekt zostanie wycieknięty, ponieważ nie istnieje shared_ptr zniszczyć i dealokować.

Rozwiązanie: użyj make_shared.

Post-C++17:

nie jest to już problemem: C++17 nakłada ograniczenie na kolejność tych operacji, w tym przypadku zapewniając, że każde wywołanie new() musi być natychmiast po zbudowaniu odpowiedniego inteligentnego wskaźnika, bez żadnej innej operacji pomiędzy nimi. Oznacza to, że do czasu wywołania drugiego new(), jest gwarantowane, że pierwszy obiekt został już zawinięty w swój inteligentny wskaźnik, zapobiegając w ten sposób wyciekom w przypadku wyrzucenia wyjątku.

Bardziej szczegółowe wyjaśnienie nowej kolejności oceny wprowadzonej przez C++17 przedstawił Barry w innej odpowiedzi.

Podziękowania dla@Remy Lebeau za zwrócenie uwagi, że jest to nadal problem w C++17 (choć mniej): konstruktor shared_ptr może nie przydzielić swojego bloku kontrolnego i rzucić, w którym to przypadku wskaźnik przekazany do niego nie jest usunięte.

Rozwiązanie: użyj make_shared.

 23
Author: user541686,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-06-20 09:12:55

new() nie powinien być używany jako mały , Jak to możliwe. Należy go stosować tak ostrożnie , Jak to możliwe. I powinien być używany tak często, jak to konieczne, jak dyktuje pragmatyzm.

Alokacja obiektów na stosie, polegająca na ich ukrytym zniszczeniu, jest prostym modelem. Jeśli wymagany zakres obiektu pasuje do tego modelu, nie ma potrzeby używania new(), z powiązanym delete() i sprawdzania wskaźników NULL. W przypadku, gdy masz wiele krótkotrwałych przedmiotów alokacja na stosie powinna zmniejszyć problemy fragmentacji sterty.

Jeśli jednak czas życia Twojego obiektu musi wykraczać poza bieżący zakres, to new() jest właściwą odpowiedzią. Po prostu upewnij się, że zwracasz uwagę na to, kiedy i jak wywołujesz delete() i możliwości wskaźników NULL, używając usuniętych obiektów i wszystkich innych gotchas, które pochodzą z wykorzystaniem wskaźników.

 17
Author: Andrew Edgecombe,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-06-28 00:38:03

W dużym stopniu, to ktoś podnoszący własne słabości do ogólnej zasady. Nie ma nic złego per se w tworzeniu obiektów za pomocą operatora new. Istnieje jakiś argument za tym, że musisz to zrobić z pewną dyscypliną: jeśli tworzysz obiekt, musisz upewnić się, że zostanie zniszczony.

Najprostszym sposobem na to jest utworzenie obiektu w pamięci automatycznej, więc C++ wie, jak go zniszczyć, gdy wyjdzie z zakres:

 {
    File foo = File("foo.dat");

    // do things

 }

Teraz, zauważ, że kiedy spadniesz z tego bloku po klamrze końcowej, foo jest poza zasięgiem. C++ wywoła swój dtor automatycznie dla Ciebie. W przeciwieństwie do Javy, nie musisz czekać, aż GC go znajdzie.

Czy napisałeś

 {
     File * foo = new File("foo.dat");

Chcesz go jednoznacznie dopasować do

     delete foo;
  }

Albo jeszcze lepiej, przydziel swój File * jako "inteligentny wskaźnik". Jeśli nie będziesz ostrożny, może to prowadzić do wycieków.

Sama odpowiedź sprawia, że błędne założenie, że jeśli nie używasz new nie przydzielasz na stercie; w rzeczywistości w C++ tego nie wiesz. Co najwyżej wiesz, że mała ilość pamięci, powiedzmy jeden wskaźnik, z pewnością jest przydzielana na stosie. Jednak zastanów się, czy implementacja pliku jest czymś w rodzaju

  class File {
    private:
      FileImpl * fd;
    public:
      File(String fn){ fd = new FileImpl(fn);}

Wtedy FileImpl będzie nadal przydzielane na stosie.

And yes, you ' d better be sure to have

     ~File(){ delete fd ; }

W klasie, jak również; bez niego, będzie wyciek pamięci z sterta, nawet jeśli nie najwyraźniej przydzielono na stercie w ogóle.

 17
Author: Charlie Martin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-06-28 00:42:58

Gdy używasz nowego, obiekty są przydzielane do sterty. Jest zwykle używany, gdy przewidujesz ekspansję. Gdy deklarujesz obiekt taki jak,

Class var;

Jest umieszczony na stosie.

Zawsze będziesz musiał wywołać destroy na obiekcie, który umieściłeś na stercie z new. Otwiera to możliwość wycieków pamięci. Przedmioty umieszczone na stosie nie są podatne na wyciek pamięci!

 15
Author: Tim,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-06-28 00:22:20

Jednym z istotnych powodów, aby uniknąć nadużywania sterty, jest wydajność-w szczególności związana z wydajnością domyślnego mechanizmu zarządzania pamięcią używanego przez C++. Podczas gdy alokacja może być dość szybka w banalnym przypadku, wykonywanie wielu new i delete na obiektach o niejednorodnej wielkości bez ścisłego porządku prowadzi nie tylko do fragmentacji pamięci, ale także komplikuje algorytm alokacji i może całkowicie zniszczyć wydajność w niektórych przypadkach.

To jest problem, który pule pamięci gdzie zostały utworzone w celu rozwiązania, co pozwala złagodzić nieodłączne wady tradycyjnych implementacji sterty, jednocześnie pozwalając na korzystanie z sterty w razie potrzeby.

[[2]}jeszcze lepiej, jednak, aby uniknąć problemu całkowicie. Jeśli możesz umieścić go na stosie, to zrób to.
 12
Author: tylerl,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-06-29 06:06:41

Myślę, że plakat miał powiedzieć You do not have to allocate everything on theheap zamiast stack.

Zasadniczo obiekty są przydzielane na stosie (jeśli rozmiar obiektu pozwala, oczywiście) ze względu na niski koszt alokacji stosu, a nie alokacji opartej na stercie, która wymaga sporo pracy alokatora i dodaje zwięzłość, ponieważ wtedy trzeba zarządzać danymi przydzielonymi na stercie.

 10
Author: Khaled Nassar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-06-28 00:14:06

Nie zgadzam się z pomysłem użycia nowego "too much". Chociaż oryginalne użycie nowego plakatu z klasami systemowymi jest trochę śmieszne. (int *i; i = new int[9999];? naprawdę? Jest dużo jaśniejsze.) Myślę, że że to właśnie to, co dostało kozę komentatora.

Podczas pracy z obiektami systemowymi, to bardzo rzadkie, że potrzebujesz więcej niż jednego odniesienia do tego samego obiektu. Dopóki wartość jest taka sama, tylko to się liczy. I obiekty systemowe zazwyczaj nie zajmują dużo miejsca w pamięci. (jeden bajt na znak, w łańcuchu). A jeśli tak, biblioteki powinny być zaprojektowane tak, aby uwzględnić zarządzanie pamięcią (jeśli są dobrze napisane). W takich przypadkach, (wszystkie oprócz jednej lub dwóch wiadomości w jego kodzie), nowe jest praktycznie bezcelowe i służy jedynie wprowadzaniu nieporozumień i potencjalnych błędów.

Kiedy jednak pracujesz z własnymi klasami/obiektami (np. klasy Line oryginalnego plakatu), musisz zacząć myśleć o problemach jak ślad pamięci, trwałość danych, itp. siebie. W tym momencie umożliwienie wielu odwołań do tej samej wartości jest nieocenione - pozwala na konstrukcje, takie jak połączone listy, słowniki i wykresy, gdzie wiele zmiennych musi nie tylko mieć tę samą wartość, ale odwoływać się do dokładnie tego samego obiektu w pamięci. Jednak Klasa Line nie ma żadnego z tych wymagań. Więc oryginalny kod plakatu nie ma absolutnie potrzeby new.

 10
Author: Chris Hayes,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-06-28 13:43:59

Dwa powody:

    To niepotrzebne w tym przypadku. Niepotrzebnie komplikujesz swój kod.
  1. przydziela miejsce na stercie i oznacza to, że musisz pamiętać o delete później, albo spowoduje to wyciek pamięci.
 3
Author: Dan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-05-20 17:46:44

new jest nowym goto.

Przypomnijmy, dlaczego goto jest tak znieważony: chociaż jest to potężne, niskopoziomowe narzędzie do kontroli przepływu, ludzie często używali go w niepotrzebnie skomplikowany sposób, który utrudniał śledzenie kodu. Co więcej, najbardziej przydatne i najłatwiejsze do odczytania wzorce zostały zakodowane w strukturyzowanych wyrażeniach programistycznych( np. for lub while); ostatecznym efektem jest to, że kod, do którego goto jest odpowiednim sposobem, jest raczej rzadki, jeśli kusisz się pisać goto, prawdopodobnie jesteś robienie rzeczy źle (chyba że naprawdę wiesz, co robisz).

new jest podobny - jest często używany do niepotrzebnie skomplikowanych i trudniejszych do odczytania rzeczy, a najbardziej użyteczne wzorce użytkowania mogą być zakodowane w różnych klasach. Ponadto, jeśli potrzebujesz użyć nowych wzorców użycia, dla których nie ma jeszcze standardowych klas, możesz napisać własne klasy, które je kodują!

Argumentowałbym nawet, że new jest gorszy niż goto, ze względu na konieczność sparowania new i delete wypowiedzi.

Podobnie jak goto, Jeśli kiedykolwiek myślisz, że musisz użyć new, prawdopodobnie robisz rzeczy źle - zwłaszcza jeśli robisz to poza implementacją klasy, której celem w życiu jest hermetyzacja dynamicznych alokacji, które musisz zrobić.

 2
Author: klutt,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-01-08 22:36:23

Głównym powodem jest to, że obiekty na stercie są zawsze trudne w użyciu i zarządzaniu niż proste wartości. Pisanie kodu, który jest łatwy do odczytania i utrzymania jest zawsze priorytetem każdego poważnego programisty.

Innym scenariuszem jest biblioteka, której używamy dostarcza semantyki wartości i sprawia, że dynamiczna alokacja nie jest potrzebna. Std::string jest dobrym przykładem.

Dla kodu zorientowanego obiektowo, użycie wskaźnika - co oznacza użycie new, aby utworzyć go wcześniej - jest koniecznością. W celu uprość złożoność zarządzania zasobami, mamy dziesiątki narzędzi, które sprawiają, że jest to tak proste, jak to możliwe, takie jak inteligentne wskaźniki. Paradygmat obiektowy lub paradygmat generyczny zakłada semantykę wartości i wymaga mniej lub nie new, tak jak na plakatach w innych miejscach.

Tradycyjne wzorce projektowe, szczególnie te wymienione w GOF book, używają new dużo, ponieważ są to typowe kody OO.

 1
Author: bingfeng zhao,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-07-31 01:27:52

Jeszcze jeden punkt do wszystkich powyższych poprawnych odpowiedzi, to zależy od tego, jaki rodzaj programowania robisz. Jądro rozwijające się na przykład w Windows - > stos jest poważnie ograniczony i możesz nie być w stanie przyjmować błędów strony, jak w trybie użytkownika.

W takich środowiskach preferowane są nowe lub podobne do C wywołania API, a nawet wymagane.

Oczywiście jest to tylko wyjątek od reguły.

 1
Author: Michael Chourdakis,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-03-22 05:53:05

new przydziela obiekty na stercie. W przeciwnym razie obiekty są przydzielane na stosie. Sprawdź różnicę między tymi dwoma .

 -6
Author: robert,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-06-28 00:11:57