С ++ - это все о владении памятью - также известной как семантика владения .
Владелец блока динамически выделяемой памяти несет ответственность за освобождение этой памяти. Таким образом, действительно возникает вопрос, кому принадлежит память.
В C ++ владение документировано типом, внутри которого заключен необработанный указатель, поэтому в хорошей (IMO) программе на C ++ очень редко ( редко , не никогда ) можно увидеть переданные необработанные указатели (поскольку исходные указатели не имеют предполагаемого владения, поэтому мы можем не указывать, кому принадлежит память, и, таким образом, без внимательного прочтения документации нельзя сказать, кто несет ответственность за владение).
И наоборот, редко можно увидеть необработанные указатели, хранящиеся в классе, каждый необработанный указатель хранится в своей собственной оболочке интеллектуального указателя. ( NB: если у вас нет объекта, вы не должны хранить его, потому что вы не можете знать, когда он выйдет из области видимости и будет уничтожен.)
Итак, вопрос:
- С какой семантикой типа собственности сталкивались люди?
- Какие стандартные классы используются для реализации этой семантики?
- В каких ситуациях вы считаете их полезными?
Давайте сохраним 1 тип семантического владения для каждого ответа, чтобы можно было голосовать за них индивидуально.
Резюме:
Концептуально интеллектуальные указатели просты, и наивная реализация проста. Я видел много попыток реализации, но неизменно они ломаются, что не очевидно для случайного использования и примеров. Поэтому я рекомендую всегда использовать хорошо протестированные интеллектуальные указатели из библиотеки, а не использовать свои собственные. std::auto_ptr
или один из интеллектуальных указателей Boost, кажется, покрывает все мои потребности.
std::auto_ptr<T>
:
Объектом владеет один человек. Передача права собственности разрешена.
Использование: это позволяет вам определять интерфейсы, которые показывают явную передачу права собственности.
boost::scoped_ptr<T>
Объектом владеет один человек. Передача права собственности НЕ допускается.
Использование: используется для демонстрации явного владения. Объект будет уничтожен деструктором или при явном сбросе.
boost::shared_ptr<T>
( std::tr1::shared_ptr<T>
)
Множественное владение. Это простой указатель с подсчетом ссылок. Когда счетчик ссылок достигает нуля, объект уничтожается.
Использование: когда у объекта может быть несколько цветов, время жизни которых не может быть определено во время компиляции.
boost::weak_ptr<T>
:
Используется shared_ptr<T>
в ситуациях, когда может произойти цикл указателей.
Использование: используется для остановки циклов от сохранения объектов, когда только цикл поддерживает общий счетчик ссылок.
источник
In C++ ownership is documented by the type a RAW pointer is wrapped inside thus in a good (IMO)
Можно ли это перефразировать? Я вообще этого не понимаю.In C++ ownership is documented by the type a RAW pointer is wrapped inside thus in a good C++ program it is very rare to see RAW pointers passed around
, Указатели RAW не имеют семантики владения. Если вы не знаете владельца, вы не знаете, кто несет ответственность за удаление объекта. Существует несколько стандартных классов, которые используются для переноса указателей (std :: shared_ptr, std :: unique_ptr и т. Д.), Которые определяют право собственности и, следовательно, определить, кто отвечает за удаление указателя.Ответы:
Для меня эти 3 вида покрывают большинство моих потребностей:
shared_ptr
- подсчет ссылок, освобождение, когда счетчик достигает нуляweak_ptr
- то же, что и выше, но это «раб» для ashared_ptr
, не может освободитьauto_ptr
- когда создание и освобождение происходит внутри одной и той же функции или когда объект должен всегда считаться единственным владельцем. Когда вы назначаете один указатель другому, второй «крадет» объект у первого.У меня есть собственная реализация для них, но они также доступны в
Boost
.Я по-прежнему передаю объекты по ссылке (
const
когда это возможно), в этом случае вызываемый метод должен предполагать, что объект жив только во время вызова.Я использую другой вид указателя, который я называю hub_ptr . Это когда у вас есть объект, который должен быть доступен из вложенных в него объектов (обычно как виртуальный базовый класс). Это можно решить, передав
weak_ptr
им, но у него нетshared_ptr
самого себя. Поскольку он знает, что эти объекты не проживут дольше него, он передает им hub_ptr (это просто оболочка шаблона для обычного указателя).источник
noncopyable
и что право собственности не может быть передано.Простая модель C ++
В большинстве модулей, которые я видел, по умолчанию предполагалось, что получение указателей не получает права собственности. Фактически, функции / методы, отказывающиеся от владения указателем, были очень редкими и явно выражали этот факт в своей документации.
Эта модель предполагает, что пользователь является владельцем только того, что он / она явно выделяет . Все остальное автоматически удаляется (при выходе из области видимости или через RAII). Это C-подобная модель, дополненная тем фактом, что большинство указателей принадлежат объектам, которые освобождают их автоматически или при необходимости (в основном при уничтожении указанных объектов), и что продолжительность жизни объектов предсказуема (RAII - ваш друг, очередной раз).
В этой модели необработанные указатели свободно распространяются и в большинстве случаев не опасны (но если разработчик достаточно умен, он / она будет использовать вместо них ссылки, когда это возможно).
Умная заостренная модель C ++
В коде, полном интеллектуальных указателей, пользователь может надеяться игнорировать время жизни объектов. Владелец никогда не является кодом пользователя: это сам интеллектуальный указатель (опять же RAII). Проблема в том, что циклические ссылки, смешанные с интеллектуальными указателями с подсчетом ссылок, могут быть смертельными , поэтому вам придется иметь дело как с общими указателями, так и со слабыми указателями. Таким образом, у вас еще есть право собственности (слабый указатель может ни на что не указывать, даже если его преимущество перед необработанным указателем состоит в том, что он может вам это сказать).
Вывод
Независимо от моделей, которые я описываю, за исключением исключений, получение указателя не получает своего владения, и по-прежнему очень важно знать, кто кому принадлежит . Даже для кода C ++, интенсивно использующего ссылки и / или умные указатели.
источник
У меня нет долевой собственности. Если да, убедитесь, что это только код, который вы не контролируете.
Это решает 100% проблем, поскольку заставляет вас понимать, как все взаимодействует.
источник
Когда ресурс совместно используется несколькими объектами. Boost shared_ptr использует подсчет ссылок, чтобы гарантировать, что ресурс не будет выделен, когда все будут завершены.
источник
std::tr1::shared_ptr<Blah>
довольно часто ваш лучший выбор.источник
Из boost есть также библиотека контейнеров указателей . Они немного эффективнее и проще в использовании, чем стандартный контейнер интеллектуальных указателей, если вы будете использовать объекты только в контексте их контейнера.
В Windows есть указатели COM (IUnknown, IDispatch и другие) и различные интеллектуальные указатели для их обработки (например, CComPtr ATL и интеллектуальные указатели, автоматически сгенерированные оператором import в Visual Studio на основе класса _com_ptr ).
источник
Когда вам нужно динамически распределять память, но вы хотите, чтобы она освобождалась в каждой точке выхода из блока.
Я считаю это полезным, так как его можно легко переустановить и отпустить, даже не беспокоясь об утечке.
источник
Я не думаю, что когда-либо имел возможность совместно владеть своим дизайном. Фактически, я только что могу придумать, что это единственный допустимый случай, это шаблон наилегчайшего веса.
источник
yasper :: ptr - это легкая альтернатива boost :: shared_ptr. Он хорошо работает в моем (пока) небольшом проекте.
На веб-странице http://yasper.sourceforge.net/ это описано следующим образом:
источник
Существует еще одна часто используемая форма единственного передаваемого владельца, и она предпочтительнее,
auto_ptr
поскольку позволяет избежать проблем, вызванныхauto_ptr
безумным искажением семантики присваивания.Я говорю не о чем другом
swap
. Любой тип с подходящейswap
функцией можно представить себе как интеллектуальную ссылку на некоторый контент, которым он владеет до тех пор, пока право собственности не будет передано другому экземпляру того же типа путем их замены. Каждый экземпляр сохраняет свою идентичность, но привязывается к новому контенту. Это похоже на безопасную повторную привязку.(Это умная ссылка, а не умный указатель, потому что вам не нужно явно разыменовать его, чтобы получить доступ к содержимому.)
Это означает, что auto_ptr становится менее необходимым - он нужен только для заполнения пробелов, в которых типы не имеют хорошей
swap
функции. Но все стандартные контейнеры работают.источник
Когда создатель объекта хочет явно передать право собственности кому-то другому. Это также способ документирования в коде, который я передаю вам, и я больше не отслеживаю его, поэтому обязательно удалите его, когда закончите.
источник