С++ Shared_ptr против.unique_ptr для управления ресурсами
-
21-12-2019 - |
Вопрос
Я обдумывал использование unique_ptr
против shared_ptr
против own_solution
.Я не учитываю последнее, так как почти наверняка ошибусь, но у меня проблема с обоими. unique_ptr
и shared_ptr
в том, что ни один из них не отражает именно то, что я хочу.Я хочу создать менеджер ресурсов, который явно владеет ресурсом, однако мне бы хотелось, чтобы менеджер ресурсов также раздавал ссылки на ресурс.
Если я использую unique_ptr
в диспетчере ресурсов и раздавать необработанные указатели, есть вероятность, что они могут сбежать в другом месте (хотя я полагаю, что это противоречило бы «контракту» класса).Если я использую shared_ptr
и раздать weak_ptr
, ничто не мешает вызывающему абоненту преобразовать weak_ptr
к shared_ptr
и сохранение этого, тем самым потенциально создавая цикл или, что еще хуже, ресурс, переживающий время жизни менеджера ресурсов.Итак, я полагаю, что я ищу weak_ptr
который не может быть преобразован в shared_ptr
.
Или я просто хочу обеспечить соблюдение контракта с помощью резких комментариев в коде?
Спасибо за любые мысли, которые могут у вас возникнуть по этому поводу.
Решение
Умные указатели, такие как shared_ptr
и unique_ptr
являются хорошими инструментами, когда у вас есть владение указатели.
Но для указателей, не владеющих указателями, т.е. наблюдение за указателями, использование необработанного указателя вполне допустимо.
Я думаю, что в вашем проекте менеджер ресурсов является единственным «владельцем» ресурсов, поэтому вы можете просто иметь некую форму интеллектуального указателя. внутри менеджер ресурсов.Например, менеджер ресурсов может иметь std::vector<std::unique_ptr<Resource>>
как член данных или даже более простой std::vector<Resource>
если ваш Resource
класс спроектирован так, чтобы его можно было правильно хранить в std::vector
.
Затем диспетчер ресурсов может предоставить внешнему пользователю только указатели наблюдения, не являющиеся владельцами, и для этого случая подходят необработанные указатели (или ссылки C++).
Конечно, важно, чтобы время жизни менеджера ресурсов превышало время жизни «клиентов ресурсов».
Другие советы
В конце концов, вы не можете заставить кого-либо слушать.Спросите у Microsoft, Apple или любого разработчика библиотеки с открытым исходным кодом, они все знают эту песню.Лучше всего оставить комментарий в правильных словах и в правильных местах.
Избегайте создания собственного класса интеллектуальных указателей, это затрудняет композицию и ухудшает читабельность.В крайнем случае попробуйте поискать в boost или в любой другой платформе, с которой уже работает ваш код.
Если у вас есть невладельцы, они либо могут быть выбраны для владения weak_ptr
s или (если гарантированно, что они останутся действительными в течение всего времени) необработанные указатели.
Если вы используете shared_ptr
внутри компании (почему вам это нужно), лучше всего предоставить weak_ptr
и необработанные указатели.
Все эти умные указатели явно обозначают политику владения.Необработанные указатели обозначают отсутствие или отсутствие владения.
auto_ptr
:Не используйте, устаревший, со слишком большим количеством ловушек даже для осторожных.unique_ptr
:Единоличное владение.shared_ptr
:Совместная собственностьweak_ptr
:Никакого права собственности, может быть удалено за вашей спиной.- необработанный указатель
- Явное отсутствие владения с гарантированным большим сроком службы
- или ручное управление собственностью.
Поэтому я полагаю, что я ищу, это отсроченная Slead_ptr, который не может быть преобразован в shared_ptr.
Вы можете раздать свой маленький вспомогательный класс:
template<typename T>
class NonConvertibleWeakPtr
{
public:
NonConvertibleWeakPtr(const std::shared_ptr<T>& p) : p_(p) {}
... // other constructors / assignment operators
bool expired() const { return p_.expired(); }
T* operator->() const { return get(); }
T& operator*() const { return *get(); }
private:
T* get() const { return p_.lock().get(); }
private:
std::weak_ptr<T> p_;
};
Это немного лучше, чем необработанный указатель, поскольку вы можете проверить, действителен ли указатель.
Пример использования:
std::shared_ptr<int> sp = std::make_shared<int>(5);
{
NonConvertibleWeakPtr<int> wp(sp);
if(!wp.expired()) {
std::cout << *wp << std::endl;
}
}
Однако пользователь все равно может использовать его неправильно, например, с помощью std::shared_ptr<T> blah(&(*wp));
, но это требует немного больше криминальной энергии.