c++ учебник с++ - Почему программисты C ++ минимизируют использование «новых»?





8 Answers

Поскольку стек является быстрым и надежным

В C ++ для выделения пространства - в стеке требуется только одна команда для каждого локального объекта области видимости в данной функции, и невозможно утечка какой-либо из этой памяти. Этот комментарий предполагал (или должен был предполагать) сказать что-то вроде «использовать стек, а не кучу».

вакансии куда деваются

Я наткнулся на вопрос «Переполнение стека». Утечка памяти с помощью std :: string при использовании std :: list <std :: string> , и один из комментариев говорит об этом:

Прекратите использовать так много. Я не вижу причины, по которой вы использовали новое, где бы вы ни были. Вы можете создавать объекты по значению на C ++, и это одно из огромных преимуществ использования языка. Вам не нужно выделять все в кучу. Прекратите думать, как программист на Java.

Я не совсем уверен, что он имеет в виду. Почему объекты должны создаваться по значению на C ++ как можно чаще, и какая разница внутри? Я неправильно понял ответ?




Объекты, созданные new должны быть в конечном итоге delete чтобы они не протекали. Деструктор не будет вызван, память не будет освобождена, весь бит. Поскольку C ++ не содержит сборку мусора, это проблема.

Объекты, созданные по значению (т.е. на стеке), автоматически умирают, когда они выходят за рамки. Деструкторный вызов вставляется компилятором, и память автоматически освобождается при возврате функции.

Умные указатели, такие как auto_ptr , shared_ptr решают проблему оборванных ссылок, но они требуют дисциплины кодирования и имеют другие проблемы (копируемость, циклы ссылок и т. Д.).

Кроме того, в сценариях с многопоточными сценариями new точка раздора между потоками; может быть влияние производительности на чрезмерное использование new . Создание объекта стека по определению thread-local, поскольку каждый поток имеет свой собственный стек.

Недостатком объектов ценности является то, что они погибают после возвращения функции хоста - вы не можете передавать ссылку на тех, кто возвращается к вызывающему, только путем копирования или возврата по значению.




В значительной степени это тот, кто поднимает свои собственные слабости до общего правила. По сути , нет ничего плохого в создании объектов с использованием new оператора. Для чего есть аргумент, так это то, что вы должны сделать это с некоторой дисциплиной: если вы создаете объект, вам нужно убедиться, что он будет уничтожен.

Самый простой способ сделать это - создать объект в автоматическом хранилище, поэтому C ++ знает, как его уничтожить, когда он выходит за рамки:

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

    // do things

 }

Теперь, обратите внимание, что, когда вы отвалитесь от этого блока после конечной скобки, foo выходит за рамки. C ++ вызовет его dtor автоматически для вас. В отличие от Java, вам не нужно ждать, пока GC ее не найдет.

Если бы вы написали

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

вы хотели бы явно сопоставить это с

     delete foo;
  }

или даже лучше, выделите свой File * как «умный указатель». Если вы не будете осторожны, это может привести к утечкам.

Сам ответ ошибочно полагает, что если вы не используете new вы не выделяете кучу; на самом деле, на C ++ вы этого не знаете. В лучшем случае вы знаете, что небольшое количество памяти, скажем, одного указателя, конечно же выделяется в стеке. Однако рассмотрите, является ли реализация файла чем-то вроде

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

то FileImpl все равно будет выделен в стеке.

И да, вы должны быть уверены, что

     ~File(){ delete fd ; }

в классе; без него вы будете утечка памяти из кучи, даже если вы явно не выделили кучу.




new() не следует использовать как можно меньше. Его следует использовать как можно более тщательно . И это должно использоваться так часто, как необходимо, как это продиктовано прагматизмом.

Выделение объектов в стеке, опираясь на их неявное разрушение, является простой моделью. Если требуемая область действия объекта подходит для этой модели, нет необходимости использовать new() , с ассоциированным delete() и проверкой указателей NULL. В случае, когда у вас есть много недолговечных объектов в стеке, необходимо уменьшить проблемы фрагментации кучи.

Однако, если время жизни вашего объекта должно выходить за пределы текущей области, то new() будет правильным ответом. Просто убедитесь, что вы обращаете внимание на то, когда и как вы вызываете delete() и возможности указателей NULL, используя удаленные объекты и все другие gotchas, которые поставляются с использованием указателей.




Когда вы используете новое, объекты выделяются в кучу. Он обычно используется, когда вы ожидаете расширения. Когда вы объявляете объект, например,

Class var;

он помещается в стек.

Вам всегда придется называть уничтожение объекта, который вы разместили в куче, с новым. Это открывает возможности утечки памяти. Объекты, помещенные в стек, не подвержены утечке памяти!




Я склонен не соглашаться с идеей использования нового «слишком много». Хотя использование оригинального плаката нового с системными классами немного смешно. ( int *i; i = new int[9999]; действительно? int i[9999]; гораздо яснее.) Я думаю, что это то, что получало козу комментатора.

Когда вы работаете с системными объектами, очень редко вам нужно больше одной ссылки на тот же самый объект. Пока значение одно и то же, это все, что имеет значение. И системные объекты обычно не занимают много места в памяти. (один байт на символ, в строке). И если они это сделают, библиотеки должны быть разработаны для учета этого управления памятью (если они хорошо написаны). В этих случаях (все, кроме одного или двух из новостей в его коде) новое практически бессмысленно и служит лишь для того, чтобы вводить путаницы и возможности для ошибок.

Однако, когда вы работаете со своими собственными классами / объектами (например, с классом Line оригинального плаката), вы должны начать думать о проблемах, таких как объем памяти, постоянство данных и т. Д. Самостоятельно. На данный момент использование нескольких ссылок на одно и то же значение неоценимо - оно позволяет создавать такие конструкции, как связанные списки, словари и графики, где несколько переменных должны иметь не только одно и то же значение, но и ссылаться на один и тот же объект в памяти. Однако класс Line не имеет ни одного из этих требований. Таким образом, исходный код плаката фактически абсолютно не нужен для new .




Две причины:

  1. В этом случае нет необходимости. Вы делаете свой код ненужным более сложным.
  2. Он выделяет пространство в куче, и это означает, что вы должны помнить, что позже delete его, или это вызовет утечку памяти.



newэто новое goto.

Напомним, почему gotoтак позорят: хотя это мощный инструмент низкого уровня для управления потоком, люди часто использовали его излишне сложными способами, из-за которых сложный код не выполнялся. Кроме того, наиболее полезные и простые для чтения шаблоны были закодированы в структурированных операциях программирования (например, forили while); конечный эффект заключается в том, что код, где gotoэто подходящий способ, довольно редок, если вы соблазняетесь писать goto, вы, вероятно, делаете что-то плохо (если вы действительно не знаете, что делаете).

newаналогичен - он часто используется, чтобы сделать вещи излишне сложными и трудными для чтения, а наиболее полезные шаблоны использования могут быть закодированы, были закодированы в различные классы. Кроме того, если вам нужно использовать любые новые шаблоны использования, для которых еще нет стандартных классов, вы можете написать свои собственные классы, которые их кодируют!

Я бы даже сказал, что newэто хуже, чем gotoиз-за необходимости пары newи deleteвысказываний.

Например goto, если вы когда-нибудь думаете, что вам нужно использовать new, вы, вероятно, делаете что-то плохое, особенно если вы делаете это за пределами реализации класса, целью которого в жизни является инкапсуляция любых динамических распределений, которые вам нужно сделать.




Related