Подтвердить что ты не робот

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, поэтому для меня довольно простота определения различной политики уничтожения по умолчанию.

4b9b3361

Ответ 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[], должен быть явно задан дебетер.