2010-12-29 3 views
3

У меня есть проект, и я хочу лучше использовать интеллектуальные указатели.Использование смарт-указателей

Основная идея - использовать их при возврате нового объекта из функции. Вопрос в том, какой умный указатель использовать? auto_ptr или shared_ptr от boost? Как я знаю, auto_ptr медленнее, но он может вернуться к «чистым» указателям.

И если я использую умный указатель на месте, где мне это не нужно, это замедлит работу?

+0

Не выбирайте интеллектуальные указатели, основанные на воспринимаемой эффективности (для одного человека абсолютно ужасно воспринимается эффективность и, как показано, обычно ошибочно). Выберите умный указатель, который показывает, как вы ожидаете, что указатель будет использоваться. Если вы передаете право собственности auto_ptr, это хорошо, если вы создаете неявно общий объект, тогда shared_ptr лучше. –

ответ

11

Что заставляет вас думать, auto_ptr медленнее, чем shared_ptr? Обычно я ожидаю, что обратное будет истинным, поскольку shared_ptr необходимо обновить счетчик ссылок.

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

  • Необработанный указатель подразумевает без права собственности; программа, которая правильно использует интеллектуальные указатели, может по-прежнему использовать необработанные указатели во многих местах, где собственность не предназначена (например, если вам нужно передать необязательную ссылку на объект в функцию, вы часто будете использовать необработанный указатель).
  • scoped_ptrsingle (т. Е. Не общий), non-Transferable собственность.
  • auto_ptrsingle (т. Е. Не общий) Передаваемый владелец.Это умный указатель, который я бы использовал, чтобы вернуть вновь построенный объект из функции (функция передает объект своему вызывающему абоненту). auto_ptr страдает из-за того, что из-за ограничений языка, когда было определено auto_ptr, его трудно использовать правильно (это дало ему очень плохую репутацию, хотя предполагаемая цель умного указателя с единой передаваемой семантикой собственности была и есть как действительные, так и полезные).
  • unique_ptr имеет ту же семантику, что и auto_ptr, но использует новые функции C++ 0x (ссылки rvalue), чтобы сделать ее намного более безопасной (менее подверженной неправильному использованию), чем auto_ptr. Если вы работаете на платформе, где доступно unique_ptr, вы должны использовать ее вместо auto_ptr.
  • shared_ptr подразумевает общее собственность. По-моему, это слишком часто используется. У этого есть много действительных применений, но должно не просто использоваться как опция по умолчанию.

Я хотел бы также добавить, что shared_ptr часто используется с STL контейнеров, так как другие классы смарт-указатель не достигают намеченной функции в этом контексте (из-за копирования значений внутри внутри контейнера). Это часто приводит к использованию shared_ptr, где совместное владение не является на самом деле предполагаемым значением. В этих случаях я предлагаю (где это возможно) использование классов указателя-указателя boost (, ptr_map и т. Д.), Которые предоставляют (обычно желаемую) семантику контейнера с передаваемым, но единственным (не общим) правом собственности.

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

[отредактирован отметить новый unique_ptr]

+1

+1 для упоминания того, что shared_ptr часто чрезмерно используется! – mmmmmmmm

+0

Во всяком случае, все еще есть некоторые чистые сценарии, где shared_ptr полезен. У меня есть потоковая структура, в которой информация потока хранится в shared_ptr, одна копия присваивается самому объекту потока и освобождается, когда потоки заканчиваются другой копией, предоставляется вызывающей стороне. Это самый чистый способ обеспечить очистку после окончания потока, но позволяет абоненту безопасно отслеживать текущее состояние потока. – mmmmmmmm

+0

Возможно, «в большинстве случаев, с чистым дизайном системы» был слишком сильным. Истинная ситуация с совместным владением не * * редко встречается (хотя и менее распространена, чем отдельная собственность). Спасибо за хороший пример. –

2

Возможно, вы должны использовать shared_ptr<>. Трудно быть более конкретным, не зная, что именно вы хотите сделать. Лучше всего прочитайте его documentation и посмотрите, делает ли он то, что вам нужно.

Разница в производительности, скорее всего, будет незначительной. Только в крайних случаях это может оказать заметное влияние, например, при копировании этих указателей много миллионов раз в секунду.

+0

Разница в производительности не будет незначительной. Поскольку накладные расходы shared_ptr - это не только увеличение и уменьшение счетчика ссылок. Существует также второе новое/удаление на объект для информации об обслуживании! И так как куча медленная, это может быть плохо в некоторых ситуациях. Кроме того, shared_ptr может привести к утечкам памяти, если у вас есть круговые ссылки (которые могут быть решены с помощью weak_ptr; но вы должны думать намного больше!). – mmmmmmmm

+0

@ rstevens: Вы можете использовать 'make_shared()', который выполняет только одно выделение. Во всяком случае, типичные узкие места производительности не используются в указателях, и я подозреваю, что проблема OPs является преждевременной оптимизацией. Также вы должны думать о утечке памяти независимо от того, какой смарт-указатель или не умный указатель вы используете. В любом случае 'shared_ptr' /' weak_ptr' упрощает обработку. – sth

1

Я предпочитаю shared_ptr, auto_ptr может вызвать массу проблем, и его использование не слишком интуитивно. Если вы ожидаете, что этот объект будет вставлен в контейнер STL, вы обязательно захотите использовать shared_ptr.

Абота вы стоите дорого, но это минимально, и вы можете игнорировать ее большую часть времени.

+1

Стоимость исполнения может быть довольно высокой! Обязательно профиль после использования интеллектуальных ptrs, чтобы узнать, приемлемо ли это воздействие. – RedX

1

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

+0

Неверно: auto_ptr может использоваться в контейнерах ... из-за его грубой характеристики ... (Использование в контейнерах является причиной этих характеристик !!!) – mmmmmmmm

+0

@rstevens: Я понятия не имею, что означает ваш комментарий. 'auto_ptr' НЕ соответствует одному из самых фундаментальных требований к элементам в стандартных контейнерах. После того, как копия или присвоение источника и приемника 'auto_ptr' не являются эквивалентными. Поэтому' auto_ptr' НЕ следует использовать в стандартных контейнерах. – Cratylus

+0

@ user384706: auto_ptr построен для использования в стандартных контейнерах, таких как std :: vector и std :: list. Это может вызвать проблемы в других контейнерах, но поскольку std :: auto_ptr и std :: - Контейнеры разрабатываются вместе, они гарантированно работают вместе. – mmmmmmmm

0

Используйте только shared_ptr. С auto_ptr вы можете иметь ТОЛЬКО ОДНУ ссылку на свой объект. Также auto_ptr не медленнее, он должен работать быстрее, чем shared_ptr.

Чтобы не задавать такие вопросы, вам нужно знать, как работают эти умные указатели.

auto_ptr просто сохраняет указатель на свой объект и уничтожает его в своем деструкторе.

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

Например

auto_ptr a_ptr (новый SomeClass);

auto_ptr another_ptr = aptr; // после этого another_ptr указывает на ваш класс, но a_ptr больше не указывает на него!

Вот почему я не рекомендую вам использовать auto_ptr.

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

Но общий указатель также не идеален.И если в вашей программе у вас есть циклический граф (когда у вас есть классы A и B, а A имеют член shared_ptr, который указывает на B и B, или объекты-члены B имеют shared_ptr, указывающие на A), чем A и B никогда не будут удалены, и вы будете есть память лизать.

Чтобы написать правильный код с shared_ptr, вам нужно быть осторожным, а также использовать weak_ptr. Для получения дополнительной информации смотрите здесь http://www.boost.org/doc/libs/1_45_0/libs/smart_ptr/smart_ptr.htm

Смежные вопросы