С ++ - это все о владении памятью - также известной как семантика владения.
Освобождение этой памяти является обязанностью владельца блока динамически выделяемой памяти. Таким образом, действительно возникает вопрос, кому принадлежит память.
В C++ право собственности документируется типом, внутри которого находится указатель сырой, поэтому в хорошей (IMO) программе на C++ очень редко (редкий, а не никогда) можно увидеть переданные необработанные указатели (поскольку исходные указатели не имеют предполагаемого владения, поэтому мы можем не указывать, кому принадлежит память, и, таким образом, без внимательного чтения документации вы не сможете определить, кто несет ответственность за право собственности).
И наоборот, редко можно увидеть необработанные указатели, хранящиеся в классе, каждый необработанный указатель хранится в своей собственной оболочке интеллектуального указателя. (Примечание: Если у вас нет объекта, вы не должны хранить его, потому что вы не можете знать, когда он выйдет из области видимости и будет уничтожен.)
Итак, вопрос:
Давайте сохраним 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> в ситуациях, когда может произойти цикл указателей.
Использование: используется для остановки циклов от сохранения объектов, когда только цикл поддерживает общий счетчик ссылок.
Я просто хотел указать, что, поскольку этот вопрос был опубликован, auto_ptr устарел в пользу (теперь стандартизированного) unique_ptr
In C++ ownership is documented by the type a RAW pointer is wrapped inside thus in a good (IMO) Можно это перефразировать? Я вообще этого не понимаю.
@lololololol Вы сократили предложение пополам. 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 и т. д.), Которые определяют право собственности и, следовательно, определить, кто отвечает за удаление указателя.
В C++ 11 + НЕ ИСПОЛЬЗУЙТЕ auto_ptr! Вместо этого используйте unique_ptr!





Когда создатель объекта хочет явно передать право собственности кому-то другому. Это также способ документирования в коде, который я передаю вам, и я больше не отслеживаю его, поэтому убедитесь, что вы удалили его, когда закончите.
Когда ресурс разделяется между несколькими объектами. Boost shared_ptr использует подсчет ссылок, чтобы гарантировать, что ресурс не будет выделен, когда все будут завершены.
std::tr1::shared_ptr<Blah> довольно часто является лучшим выбором.
shared_ptr - самый распространенный. Но есть еще много чего. У каждого своя модель использования и хорошие и плохие места для подачи иска. Было бы неплохо еще немного описания.
Если вы застряли со старым компилятором, boost :: shared_ptr <blah> - это то, на чем основан std :: tr1 :: shared_ptr <blah>. Это достаточно простой класс, и вы, вероятно, сможете скопировать его из Boost и использовать, даже если ваш компилятор не поддерживается последней версией Boost.
Когда вам нужно динамически распределять память, но вы хотите быть уверенным, что она освобождается в каждой точке выхода из блока.
Я считаю это полезным, так как его можно легко переустановить и отпустить, даже не беспокоясь об утечке.
Для меня эти 3 вида покрывают большую часть моих потребностей:
shared_ptr - счетчик ссылок, освобождение, когда счетчик достигает нуля
weak_ptr - то же, что и выше, но это "подчиненный" для shared_ptr, не может освободить
auto_ptr - когда создание и освобождение происходит внутри одной и той же функции, или когда объект всегда должен рассматриваться как единственный владелец. Когда вы назначаете один указатель другому, второй «крадет» объект у первого.
У меня есть собственная реализация для них, но они также доступны в Boost.
Я по-прежнему передаю объекты по ссылке (const, когда это возможно), в этом случае вызываемый метод должен предполагать, что объект жив только во время вызова.
Я использую другой вид указателя, который я называю hub_ptr. Это когда у вас есть объект, который должен быть доступен из вложенных в него объектов (обычно как виртуальный базовый класс). Это можно решить, передав им weak_ptr, но у него нет shared_ptr. Поскольку он знает, что эти объекты не проживут дольше него, он передает им hub_ptr (это просто оболочка шаблона для обычного указателя).
Вместо того, чтобы создавать свой собственный класс указателя (hub_ptr), почему бы вам просто не передать * this этим объектам и позволить им сохранить его как ссылку? Поскольку вы даже признаете, что объекты будут уничтожены одновременно с классом-владельцем, я не понимаю смысла перепрыгивать через столько обручей.
По сути, это контракт на дизайн, чтобы прояснить ситуацию. Когда дочерний объект получает hub_ptr, он знает, что указанный объект не будет уничтожен в течение жизни дочернего объекта, и не имеет на него права собственности. И содержащиеся, и контейнерные объекты подчиняются четкому набору правил. Если вы используете голый указатель, правила можно задокументировать, но компилятор и код не будут их применять.
Также обратите внимание, что у вас может быть #ifdefs для определения типа hub_ptr на голый указатель в сборках выпуска, поэтому накладные расходы будут существовать только в сборке отладки.
Обратите внимание, что Документация Boost противоречит вашему описанию scoped_ptr. В нем указано, что это noncopyable и что право собственности не может быть передано.
@ Алек Томас, ты прав. Я думал об auto_ptr и написал scoped_ptr. Исправлено.
Я не думаю, что когда-либо имел возможность совместно владеть своим дизайном. Фактически, с макушки головы я могу придумать только один допустимый случай - это модель наилегчайшего веса.
У меня нет долевой собственности. Если да, убедитесь, что это только код, который вы не контролируете.
Это решает 100% проблем, поскольку заставляет вас понимать, как все взаимодействует.
В большинстве модулей, которые я видел, по умолчанию предполагалось, что получатели указателей были нет, получающими владение. Фактически, функции / методы, отказывающиеся от владения указателем, были очень редкими и явно выражали этот факт в своей документации.
Эта модель предполагает, что пользователь является владельцем только того, что он явно выделяет.. Все остальное автоматически удаляется (при выходе из области действия или через RAII). Это C-подобная модель, расширенная тем фактом, что большинство указателей принадлежат объектам, которые освобождают их автоматически или при необходимости (в основном при уничтожении указанных объектов), и что продолжительность жизни объектов предсказуема (RAII - ваш друг, опять таки).
В этой модели необработанные указатели распространяются свободно и в большинстве случаев не опасны (но если разработчик достаточно умен, он / она будет использовать вместо них ссылки, когда это возможно).
В коде, полном интеллектуальных указателей, пользователь может надеяться игнорировать время жизни объектов. Владелец никогда не является кодом пользователя: это сам интеллектуальный указатель (опять же RAII). Проблема в том, что циклические ссылки, смешанные с умными указателями с подсчетом ссылок, могут быть смертельными., поэтому вам придется иметь дело как с общими указателями, так и со слабыми указателями. Таким образом, у вас все еще есть право собственности (слабый указатель может ни на что не указывать, даже если его преимущество перед необработанным указателем состоит в том, что он может вам это сказать).
Независимо от моделей, которые я описываю, если исключение, получение указателя - это нет, получающее право собственности и по-прежнему очень важно знать, кто кому принадлежит. Даже для кода C++, интенсивно использующего ссылки и / или умные указатели.
yasper :: ptr - это легкая альтернатива boost :: shared_ptr. Он хорошо работает в моем (пока) небольшом проекте.
На веб-странице http://yasper.sourceforge.net/ это описано следующим образом:
Why write another C++ smart pointer? There already exist several high quality smart pointer implementations for C++, most prominently the Boost pointer pantheon and Loki's SmartPtr. For a good comparison of smart pointer implementations and when their use is appropriate please read Herb Sutter's The New C++: Smart(er) Pointers. In contrast with the expansive features of other libraries, Yasper is a narrowly focused reference counting pointer. It corresponds closely with Boost's shared_ptr and Loki's RefCounted/AllowConversion policies. Yasper allows C++ programmers to forget about memory management without introducing the Boost's large dependencies or having to learn about Loki's complicated policy templates. Philosophy
* small (contained in single header) * simple (nothing fancy in the code, easy to understand) * maximum compatibility (drop in replacement for dumb pointers)The last point can be dangerous, since yasper permits risky (yet useful) actions (such as assignment to raw pointers and manual release) disallowed by other implementations. Be careful, only use those features if you know what you're doing!
Из буста еще есть библиотека контейнер указателя. Они немного эффективнее и проще в использовании, чем стандартный контейнер интеллектуальных указателей, если вы будете использовать объекты только в контексте их контейнера.
В Windows есть указатели COM (IUnknown, IDispatch и другие) и различные интеллектуальные указатели для их обработки (например, CComPtr ATL и интеллектуальные указатели, автоматически сгенерированные оператором import в Visual Studio на основе класса _com_ptr ).
Существует еще одна часто используемая форма единственного передаваемого владельца, и она предпочтительнее auto_ptr, поскольку позволяет избежать проблем, вызванных безумным искажением семантики присваивания auto_ptr.
Я говорю не о чем другом, как о swap. Любой тип с подходящей функцией swap можно представить как умная ссылка для некоторого контента, которым он владеет до тех пор, пока право собственности не будет передано другому экземпляру того же типа путем их замены. Каждый экземпляр сохраняет свою идентичность, но привязывается к новому контенту. Это похоже на безопасную повторную привязку.
(Это умная ссылка, а не умный указатель, потому что вам не нужно явно разыменовать его, чтобы получить доступ к содержимому.)
Это означает, что auto_ptr становится менее необходимым - он нужен только для заполнения пробелов, в которых типы не имеют хорошей функции swap. Но все стандартные контейнеры работают.
Возможно, это станет менее необходимым (я бы сказал, что scoped_ptr делает это менее необходимым, чем это), но это никуда не денется. Наличие функции подкачки вам совсем не поможет, если вы выделяете что-то в куче, и кто-то бросает перед удалением, или вы просто забываете.
Это именно то, что я сказал в последнем абзаце.
?? Какой был вопрос?