Умные указатели: или кто владеет тобой, детка? [закрытый]
C++ - это все о собственности памяти
Ака"Семантика Собственности"
это ответственность владельца куска динамически выделенной памяти, чтобы освободить эту память. Поэтому вопрос в том, кому принадлежит память.
в C++ владение документируется типом необработанного указателя, завернутого внутри, таким образом, в хорошей (IMO) программе C++ очень редко [редко не никогда] видеть необработанные указатели, передаваемые (поскольку необработанные указатели не имеют вывода владение, таким образом, мы не можем сказать, кто владеет памятью, и, таким образом, без тщательного чтения документации вы не можете сказать, кто несет ответственность за владение).
и наоборот, редко можно увидеть необработанные указатели, хранящиеся в классе, каждый необработанный указатель хранится в собственной оболочке смарт-указателя. (Б. Н.: если у вас нет объекта, вы не должны хранить его, потому что вы не можете знать, когда он выйдет из области и будет уничтожен.)
Так вопрос:
- С каким типом собственности сталкивались люди?
- какие стандартные классы используются для реализации этой семантики?
- какие ситуации вы считаете полезными?
позволяет сохранить 1 тип семантической собственности на ответ, чтобы их можно было голосовать вверх и вниз по отдельности
резюме:
концептуально умные указатели просты, а наивные реализации просты. Я видел много попытки реализации, но неизменно они нарушаются каким-то образом, что не очевидно для случайного использования и примеров. Поэтому я рекомендую всегда использовать хорошо протестированные "умные указатели" из библиотеки, а не сворачивать свои собственные. std:: auto_ptr или один из интеллектуальных указателей boost, похоже, охватывают все мои потребности.
std:: auto_ptr:
объект принадлежит одному человеку.
Но передача права собственности разрешена.
использование:
======
Этот позволяет определить интерфейсы, которые показывают явную передачу права собственности.
boost:: scoped_ptr
объект принадлежит одному человеку.
Передача права собственности не допускается.
использование:
======
Используется для отображения явного владения.
Объект будет уничтожен деструктором или при явном сбросе.
boost:: shared_ptr (std::tr1:: shared_ptr)
множественные собственности.
Это простой указатель подсчета ссылок. Когда счетчик ссылок достигает нуля, объект уничтожается.
использование:
======
Когда объект может иметь несколько цветов в жизни, что не может быть определено во время компиляции.
boost:: weak_ptr
используется с shared_ptr.
В ситуациях, когда цикл указателей может случаться.
использование:
======
Используется для остановки циклов от сохранения объектов, когда только цикл поддерживает общий refcount.
11 ответов
для меня эти 3 вида покрывает большинство моих потребностей:
shared_ptr
- ссылка-подсчитано, освобождение, когда счетчик достигает нуля
weak_ptr
- то же, что и выше, но это 'раб' для shared_ptr
, не может освободить
auto_ptr
- когда создание и освобождение происходят внутри одной и той же функции или когда объект должен считаться только одним владельцем. Когда вы назначаете один указатель другому, второй "крадет" объект из первый.
у меня есть своя реализация для них, но они также доступны в Boost
.
Я все еще передаю объекты по ссылке (const
когда это возможно), в этом случае вызываемый метод должен предполагать, что объект жив только во время вызова.
есть другой вид указателя, который я использую, который я называю hub_ptr. Это когда у вас есть объект, который должен быть доступен из вложенных в него объектов (обычно как виртуальный базовый класс.) Это можно решить, передав weak_ptr
, а не shared_ptr
для себя. Поскольку он знает, что эти объекты не будут жить дольше, чем он, он передает им hub_ptr (это просто оболочка шаблона для обычного указателя).
Простая Модель C++
в большинстве модулей, которые я видел, по умолчанию предполагалось, что получение указателей было не получение собственности. Фактически, функции / методы, отказывающиеся от владения указателем, были очень редкими и явно выражали этот факт в своей документации.
эта модель предполагает, что пользователь является владельцем только того, что он явно выделяет. Все остальное автоматически утилизируется (при выходе из области или через RAII). Это C-подобная модель, расширенная тем, что большинство указателей принадлежат объектам, которые будут освобождать их автоматически или при необходимости (в основном при уничтожении указанных объектов), и что продолжительность жизни объектов предсказуема (RAII-ваш друг, снова).
в этой модели необработанные указатели свободно циркулируют и в основном не опасны (но если разработчик достаточно умен, он/она будет использовать ссылки, когда это возможно).
- raw указатели
- std:: auto_ptr
- boost:: scoped_ptr
Умная Остроконечная Модель C++
в коде, полном интеллектуальных указателей, пользователь может надеяться игнорировать время жизни объектов. Владелец никогда не является кодом пользователя: это сам интеллектуальный указатель (RAII, снова). проблема в том, что круговые ссылки, смешанные со ссылочными умными указателями, могут быть смертельными, поэтому вам придется иметь дело как с общими указателями, так и со слабыми указателями. Таким образом, у вас все еще есть право собственности (слабый указатель может ничего не указывать, даже если его преимущество перед необработанным указателем заключается в том, что он может вам это сказать).
- boost:: shared_ptr
- boost:: weak_ptr
вывод
независимо от того, какие модели я описываю,Если исключение, получение указателя не получение права собственности и по-прежнему очень важно знать, кто кому принадлежит. Даже для кода на C++ в значительной степени используются ссылки и/или интеллектуальные указатели.
не имеют совместного владения. Если вы это сделаете, убедитесь, что это только с кодом, который вы не контролируете.
Это решает 100% проблем, так как это заставляет вас понять, как все взаимодействует.
- Долевой Собственности
- boost:: shared_ptr
когда ресурс совместно используется несколькими объектами. Boost shared_ptr использует подсчет ссылок, чтобы убедиться, что ресурс де-выделен, когда все finsihed.
из boost, есть также указатель контейнер библиотека. Они немного эффективнее и проще в использовании, чем стандартный контейнер интеллектуальных указателей, если вы будете использовать объекты только в контексте их контейнера.
в Windows есть com-указатели (IUnknown, IDispatch и friends) и различные интеллектуальные указатели для их обработки (например, ATL ccomptr при помощи и интеллектуальные указатели, автоматически генерируемые инструкцией "import" в Visual Студия на основе _com_ptr класс).
- Один Хозяин
- boost:: scoped_ptr
когда вам нужно выделить память динамически, но хотите быть уверены, что она освобождается от каждой точки выхода блока.
Я нахожу это полезным, так как он может быть легко переустановлен и выпущен без необходимости беспокоиться об утечке
Я не думаю, что когда-либо был в состоянии разделить право собственности на мой дизайн. На самом деле, с моей головы единственный действительный случай, о котором я могу думать, - это шаблон веса мухи.
yasper::ptr-это легкий, boost:: shared_ptr, как альтернатива. Он хорошо работает в моем (пока) небольшом проекте.
на веб-странице в http://yasper.sourceforge.net/ это описано следующим образом:
зачем писать другой умный указатель на C++? Уже существуют несколько качественные реализации интеллектуальных указателей для C++, наиболее заметно повышение пантеон указателя и SmartPtr Локи. Для хорошего сравнения smart pointer реализации и когда их использование соответствующие прочтите Херб Саттер Новые указатели C++: Smart(er). В контраст с экспансивными функциями из других библиотек, Yasper узконаправленный отсчет ссылок указатель. Оно соответствует близко с Boost shared_ptr и Локи RefCounted/AllowConversion политики. Yasper позволяет программистам C++ забудьте об управлении памятью без внедрение большой прирост по зависимости или узнать о Локи сложные шаблоны политики. Философия!--2-->
* small (contained in single header) * simple (nothing fancy in the code, easy to understand) * maximum compatibility (drop in replacement for dumb pointers)
последняя точка может быть опасной, так как yasper разрешает рискованный (но полезный) действия (например, присвоение raw указатели и ручное отключение) запрещен другими реализациями. Будьте осторожны, используйте только эти функции, если ты знаешь, что делаешь!
существует еще одна часто используемая форма single-transferable-owner, и она предпочтительнее auto_ptr
ведь это позволяет избежать проблем, вызванных auto_ptr
безумная коррупция семантики присвоения.
Я говорю не о ком ином, как о swap
. Любой тип с подходящим swap
функция может быть понята как smart reference к некоторому контенту, которым он владеет до тех пор, пока владение не будет передано другому экземпляру того же типа, путем замены их. Каждый экземпляр сохраняет свою идентичность, но привязывается к новому содержимому. Это как безопасно rebindable ссылка.
(это интеллектуальная ссылка, а не умный указатель, потому что вам не нужно явно разыменовать его, чтобы получить содержимое.)
это означает, что auto_ptr становится менее необходимым - это необходимо только для заполнения пробелов, где типы не имеют хорошего
- один владелец: он же delete on Copy
- std:: auto_ptr
когда Создатель объекта хочет явно передать право собственности кому-то другому. Это также способ документирования в коде, который я даю вам, и я больше не отслеживаю его, поэтому убедитесь, что вы удалите его, когда закончите.