Foo* f = новый Foo хороший код C++

Прочтение старого Журнала C++, который я имел, я заметил что-то.

Одна из статей утверждала это

Foo *f = new Foo();

был почти недопустимый профессиональный код C++ в общем и целом, и автоматическое решение для управления памятью было соответствующим.

Это так?

править: перефразированный: действительно ли управление непосредственной памятью недопустимо для нового кода C++ в целом? Должен auto_ptr (или другие обертки управления) использоваться для самого нового кода?

16
задан Paul Nathan 11 January 2010 в 17:56
поделиться

10 ответов

Этот пример очень Java, как.
В C ++ мы используем только динамическое управление памятью, если это необходимо.
Лучшая альтернатива - просто объявить локальную переменную.

{
    Foo    f;

    // use f

} // f goes out of scope and is immediately destroyed here.

Если вы должны использовать динамическую память, то используйте умный указатель.

// In C++14
{
    std::unique_ptr<Foo>  f = std::make_unique<Foo>(); // no need for new anymore
}

// In C++11
{
    std::unique_ptr<Foo>  f(new Foo);  // See Description below.
}

// In C++03
{
    std::auto_ptr<Foo>    f(new Foo);  // the smart pointer f owns the pointer.
                                       // At some point f may give up ownership to another
                                       // object. If not then f will automatically delete
                                       // the pointer when it goes out of scope..

}

Есть целый Bued OS Smart Picketers предоставил INT STD :: и Boost :: (теперь некоторые находятся в STD :: Tr1) Выберите подходящее и используйте его для управления продолжительностью продолжительности жизни вашего объекта.

См. Учетные указатели : или кому принадлежит вам, детка?

Технически вы можете использовать новое / удалить, чтобы сделать управление памятью.
Но в реальном C ++ код почти никогда не делал. Там почти всегда лучшая альтернатива для управления памятью вручную.

Простой пример является STD :: вектор. Под крышками он использует новый и удалять. Но вы никогда не сможете сказать снаружи. Это полностью прозрачно для пользователя класса. Все, что знает, что пользователь состоит в том, что вектором будет принимать владение объектом, и он будет уничтожен, когда вектор разрушен.

20
ответ дан 30 November 2019 в 15:30
поделиться

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

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

Хорошим началом был бы какой-нибудь умный класс указателей, например boost::shared_ptr, boost::scoped_ptr. ( Они будут частью стандарта C++0x, так что не бойтесь их ;) )

.
7
ответ дан 30 November 2019 в 15:30
поделиться
-

Я думаю, проблема всех этих «... лучших практик ...» вопросов состоит в том, что все они считают код без контекста. Если вы спросите «в целом», я должен признать, что прямое управление памятью совершенно приемлемо. Он синтаксически законно, и он не нарушает любую языковую семантику.

Что касается альтернатив (переменные стека, умные указатели и т. Д.), Все они имеют свои недостатки. И ни один из них не имеет гибкости, у меня есть прямое управление памятью. Цена, которую вы должны заплатить за такую ​​гибкость, это ваше время отладки, и вы должны знать все риски.

8
ответ дан 30 November 2019 в 15:30
поделиться

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

6
ответ дан 30 November 2019 в 15:30
поделиться

В общем нет, но общий случай не является общим случаем. Вот почему автоматические схемы, такие как Райи, были изобретены в первую очередь.

От ответа Я написал другому вопросу:

Работа программиста - это выразить вещи элегантно на своем языке выбор.

C ++ имеет очень хорошую семантику для Строительство и разрушение Объекты на стеке. Если ресурс может быть выделено в течение длительности Объем блока, затем хороший программист вероятно, сделает этот путь наименее сопротивление. Срок службы объекта разграниченные брекетами, которые, вероятно, Уже там все равно.

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

Не может быть ни одного родителя. Следующая лучшая вещь - последовательность приемные родители. Это что AUTO_PTR для. Все еще довольно хорошо, потому что программист должен знать Какой конкретный родитель является владельцем. Срок службы объекта разграничен срок службы его последовательности владельцы. Один шаг вниз по цепочке в детерминизм и на SE Elegance Shared_ptr : срок службы, разграниченные Союз пула владельцев.

> Но, может быть, этот ресурс не одновременно с любым другим объектом, установленным объектов или контрольный поток в система. Это создано на каком-то событии происходит и уничтожено на другом мероприятие. Хотя много инструменты для разграничения жизни делегации и другие жизненные жизни, они не достаточно для вычисления любого произвольная функция. Итак, программист может принять решение написать функцию несколько переменных, чтобы определить, Объект возникает или исчезает и звонить New и Удалить .

Наконец, функции записи могут быть жесткий. Может быть, правила, регулирующие объект займет слишком много времени и Память на самом деле вычислять! И это может быть просто трудно выразить их элегантно, возвращаясь к моему Оригинальная точка. Так что для этого у нас есть Коллекция мусора: объект Срок службы ограничен, когда вы хотите Это и когда вы этого не сделаете.

1
ответ дан 30 November 2019 в 15:30
поделиться

Если вы используете исключения, этот код практически гарантирован, чтобы привести к утечкам. Даже если вы отключаете исключения, уборка очень проста, когда вручную сопряжение новых с удалением.

6
ответ дан 30 November 2019 в 15:30
поделиться

Я перестал писать такой код некоторое время назад. Есть несколько альтернатив:

Scope-based deletion

{
    Foo foo;
    // done with foo, release
}

scoped_ptr для scope-based dynamical allocation

{
    scoped_ptr<Foo> foo( new Foo() );
    // done with foo, release
}

shared_ptr для вещей, которые должны быть обработаны во многих местах

shared_ptr<Foo> foo;
{ 
    foo.reset( new Foo() );
} 
// still alive
shared_ptr<Foo> bar = foo; // pointer copy
...
foo.reset(); // Foo still lives via bar
bar.reset(); // released

Facory-based resource management

Foo* foo = fooFactory.build();
...
fooFactory.release( foo ); // or it will be 
                           // automatically released 
                           // on factory destruction
2
ответ дан 30 November 2019 в 15:30
поделиться

В целом ваш пример не является безопасным исключением, и поэтому не следует использовать. Если линия непосредственно следуй за новыми бросками? Стек раскручивается, и вы только что просочились память. Умный указатель позаботится об этом для вас в составе стека, расслабиться. Если вы склонны не обращаться с исключениями, то нет ничьей обратно за пределы вопросов Raii.

0
ответ дан 30 November 2019 в 15:30
поделиться

Прежде всего, я считаю, что это должно быть foo * f = new foo ();

и причина, по которой я не люблю использовать этот синтаксис, потому что это легко Забудьте добавить Удалить в конце кода и оставить память A-Leakin '.

0
ответ дан 30 November 2019 в 15:30
поделиться
121 --- 3440558-

Это зависит от именно то, что мы имеем в виду.

  • Должен New Никогда не использоваться для выделения памяти? Конечно, надо, у нас нет другого варианта. Новое - это Путь , способ динамически выделения объектов в C ++. Когда нам нужно динамически выделять объект типа T, мы делаем New T (...) .
  • Должен NEW по умолчанию по умолчанию , когда мы хотим создать новый объект? Нет . В Java или C #, NEW используется для создания новых объектов, поэтому вы используете его везде. В C ++ он используется только для выделения кучи. Почти все объекты должны быть выделены стеками (или созданы устанавливаемыми членами класса), чтобы правила облигации языка помогают нам управлять своими жизнеразнами. Новое не часто не требуется. Обычно, когда мы хотим выделить новые объекты на куче, вы делаете это как часть большей коллекции, в этом случае вы должны просто нажать на свой контейнер STL, и позвольте ему беспокоиться о распределении и деливках памяти. Если вам просто нужно один объект, он обычно может быть создан в качестве класса или локальной переменной, без использования NEW .
  • Должен New присутствовать в вашем бизнес-коде? Редко, если когда-либо. Как упомянуто выше, это может и должно быть, как правило, быть скрыты внутри классов обертки. STD :: Vector Например, динамически распределяет память им потребности. Таким образом, пользователь в вектор не должен заботиться. Я просто создаю вектор на стеке, и это заботится о распределении кучи для меня. Когда вектор или другой класс контейнера не подходит, мы можем захотеть написать нашу собственную оболочку Raii, которое выделяет некоторую память в конструкторе с новым и выпускает его в деструктор. И эта обертка может быть выделена стеком, поэтому пользователь класса никогда не должен вызывать new .

Один из статей утверждал, что foo * f = new foo (); был почти неприемлемым профессиональным кодом C ++ по и крупным, и было уместно автоматическое решение для управления памятью.

Если они означают, что я думаю, они имеют в виду, тогда они правы. Как я уже сказал выше, New обычно должен быть скрыт в классах обертки, где автоматическое управление памятью (в форме спецификации срока службы и объекты, имеющие их деструкторы, вызванные, когда они выходят из-за объема) могут позаботиться об этом для тебя. Статья не говорит: «Никогда не выделяйте что-нибудь на куче» или никогда не используйте New », но просто« когда вы используете New , не просто храните указатель на выделенная память. Поместите его в какой-то класс, который может позаботиться о том, чтобы освободить его, когда он выходит из неисправности.

, а не foo * f = new foo (); , вы должны использовать один из них:

Scoped_Foo f; // just create a wrapper which *internally* allocates what it needs on the heap and frees it when it goes out of scope
shared_ptr<Foo> f = new Foo(); // if you *do* need to dynamically allocate an object, place the resulting pointer inside a smart pointer of some sort. Depending on circumstances, scoped_ptr, or auto_ptr may be preferable. Or in C++0x, unique_ptr
std::vector<Foo> v; v.push_back(Foo()); // place the object in a vector or another container, and let that worry about memory allocations.
4
ответ дан 30 November 2019 в 15:30
поделиться
Другие вопросы по тегам:

Похожие вопросы: