Unique_ptr <> v shared_ptr <> в отношении политики уничтожения
Я преподавал себе умные указатели, которые являются частью С++ 0x, и наткнулся на то, что кажется мне непоследовательным. В частности, как обрабатываются политики уничтожения unique_ptr < > и shared_ptr < > .
Для unique_ptr < > вы можете специализировать std:: default_delete < > и затем, если вы явно не запрашиваете другую политику уничтожения, будет использоваться новый по умолчанию.
Рассмотрим следующее:
struct some_c_type;
some_c_type *construct_some_c_type();
void destruct_some_c_type(some_c_type *);
namespace std {
template <> struct default_delete<some_c_type> {
void operator()(some_c_type *ptr) {
destruct_some_c_type(ptr);
}
};
}
Теперь, как только это произойдет, unique_ptr < > будет использовать соответствующую политику уничтожения по умолчанию:
// Because of the specialization, this will use destruct_some_c_type
std::unique_ptr<some_c_type> var(construct_some_c_type());
Теперь сравните это с shared_ptr < > . С shared_ptr < > вам нужно явно запросить соответствующую политику уничтожения или по умолчанию использовать оператор delete:
// error, will use operator delete
std::shared_ptr<some_c_type> var(construct_some_c_type());
// correct, must explicitly request the destruction policy
std::shared_ptr<some_c_type> var(construct_some_c_type(),
std::default_delete<some_c_type>());
Два вопроса.
- Правильно ли, что shared_ptr < > требует, чтобы политика уничтожения была указана каждый раз, когда она использовалась, или я что-то не хватает?
- Если я чего-то не упускаю, любая идея, почему эти две разные?
P.S. Причина, по которой я забочусь об этом, - моя компания делает много смешанных программ на C и С++. Код С++ часто должен использовать объекты стиля C, поэтому для меня довольно простота определения различной политики уничтожения по умолчанию.
Ответы
Ответ 1
Я думаю, что вопрос сводится к тому, что std:: shared_ptr не может иметь связанного делетера (в этом случае он просто вызывает delete
), а не по умолчанию по умолчанию std::default_delete
. (Не знаю. Если бы намерение заключалось в том, что default_delete
предназначен для специализации, можно было бы ожидать, что он будет использоваться shared_ptr
.)
В противном случае есть компромиссы.
Лучше иметь меньше аргументов шаблона. В рекомендации Boost упоминается, что это позволяет factory изменять схему распределения без изменения, влияющего на пользователя factory.
A unique_ptr
, с другой стороны, должен быть очень легким. Как бы вы храните делектор с нулевыми служебными служебными данными (в случае функтора без членов), если он не был частью типа (GCC использует кортеж, где безразмерные объекты не занимают пространство памяти)?
Субъективно, я думаю, я бы предпочел:
unique_ptr<FILE, FCloser> f(fopen(x, y));
к
unique_ptr<FILE> f(fopen(x, y)); //default_delete<FILE> has been specialized
В первом случае ничего не угадать. Если ресурс не исходит от new
или new[]
, должен быть явно задан дебетер.