Здесь есть несколько вопросов, связанных в один, так что потерпите меня, если я не отвечу на них в порядке, который вы ожидаете.
Большинство советов по SO говорят об использовании shared_ptr вместо обычных указателей.
Да и нет. К сожалению, некоторые пользователи SO рекомендуют shared_ptr
, как если бы это была серебряная пуля для решения всех проблем, связанных с управлением памятью. Это не . Большинство советов говорят о том, чтобы не использовать голые указатели, что существенно отличается.
Настоящий совет - использовать умных менеджеров : будь то умные указатели (unique_ptr
, scoped_ptr
, shared_ptr
, auto_ptr
), умные контейнеры (ptr_vector
, ptr_map
) или нестандартные решения для сложных задач (на основе Boost.MultiIndex, с использованием навязчивых счетчиков и т. д.).
Вы должны выбрать умный менеджер для использования в зависимости от необходимости. Наиболее примечательно, если вам не нужно делиться правами собственности на объект, тогда вам не следует использовать shared_ptr
.
Что такое COW?
COW (Copy-On-Write) - это совместное использование данных для «сохранения» памяти и удешевления копирования ... без изменения семантики программы.
С пользовательской точки зрения, неважно, std::string
использует COW или нет. При изменении строки все остальные строки не затрагиваются.
Идея, лежащая в основе COW, заключается в следующем:
- если вы являетесь единственным владельцем данных, вы можете изменить их
- если нет, то вы должны скопировать его, а затем использовать вместо него
Похоже на shared_ptr
, так почему бы и нет?
Это похоже, но оба предназначены для решения разных проблем, и в результате они слегка различаются.
Беда в том, что, поскольку shared_ptr
предназначен для бесперебойной работы независимо от того, является ли право собственности общим или нет, COW трудно реализовать тест «если единственный владелец». Примечательно, что взаимодействие weak_ptr
затрудняет.
Это возможно, очевидно. Ключ не для утечки shared_ptr
, вообще, и не использовать weak_ptr
(они все равно бесполезны для COW).
Это имеет значение?
Нет, не совсем. Доказано, что COW не так уж и хорош. В большинстве случаев это микрооптимизация ... и микропессимизация одновременно. Вы можете сэкономить некоторую память (хотя это работает, только если вы не копируете большие объекты), но вы усложняете алгоритм, что может замедлить выполнение (вы вводите тесты).
Мой совет - не использовать COW. И не использовать эти shared_ptr
.
Лично я бы либо:
- используйте
boost::ptr_vector<Ingredient>
вместо std::vector< boost::shared_ptr<Ingredient> >
(вам не нужно делиться)
- создайте
IngredientFactory
, который будет создавать (и управлять) ингредиентами, и вернуть Ingredient const&
, Factory
должен пережить любой Receipt
.
EDIT : после комментария Xeo кажется, что последний элемент (IngredientFactory
) довольно лаконичен ...
В случае IngredientFactory
объект Receipt
будет содержать std::vector<Ingredient const*>
. Обратите внимание на необработанный указатель:
Receipt
не отвечает за память, но предоставляется доступ к ней
- существует неявная гарантия того, что указанный объект будет оставаться действительным дольше, чем
Receipt
объект
Можно использовать сырые (обнаженные) указатели, если вы обращаетесь с ними так, как если бы вы указывали. Вам просто нужно остерегаться потенциальной аннулирования, и вам предлагается переустановить их, если вы того пожелаете, - и вы доверяете провайдеру заботиться о аспектах управления временем жизни / памятью.