Тонкости использования пользовательских функций удаления со стандартными умными указателями
Я пытаюсь использовать возможности стандартных умных указателей по заданию пользовательских функций (политик) удаления. У меня есть два вопроса.
Могу ли я задать для
std::unique_ptrиstd::shared_ptrпользовательскую функцию удаления без указания в списке параметров шаблона конкретного типа функции удаления?Например, у меня не получается сделать так:
std::unique_ptr<int> ui{ new int(), [](int*){ ... } };Но получается так:
std::unique_ptr<int, std::function<void(int*)>> ui{ new int(), [](int*){ ... } };Я не совсем понимаю, почему так.
Будет ли копироваться/перемещаться заданная функция удаления при копировании/перемещении соответствующего умного указателя? Всегда ли это будет происходить, или есть исключения?
Ответы (1 шт):
М. Скотт - Эффективный и современный C++ 11-14 (гл. 4.3):
Подобно std::unique_ptr, std::shared_ptr в качестве механизма удаления ресурса по умолчанию использует delete, но подерживает и пользовательские удалители. Однако дизайн этой поддержки отличается от дизайна для std::unique_ptr. Для std::unique_ptr тип удалителя является частью типа интеллектуального указателя. Для std::shared_ptr это не так:
auto loggingDel = [] (Widget *pw) // Пользовательскй удалитель { makeLogEntry(pw); delete pw; }; std::unique_ptr< // Тип удалителя является Widget, decltype(loggingDel) // частью типа указателя > upw (new Widget, loggingDel); std::shared_ptr<Widget> // Тип удалителя не является spw (new Widget, loggingDel); // частью типа указателя
Т.к. shared_ptr с разными удалителями являются объектами одного и того же типа, то они могут быть помещены в один и тот же контейнер, присвоены один другому и т.п. С unique_ptr такое не выйдет, т.к. тип удалителя является частью типа самого unique_ptr.
Следовательно:
- Для
unique_ptrтип пользовательской функции удаления нужно явно задать через параметр шаблонаunique_ptr, либо воспользоваться автоматическим выведением типа, а дляshared_ptrэто всегда вызываемый объект с параметромT*.
Что касается второго вопроса. Для unique_ptr пользовательский удалитель хранится в виде указателя на функцию или функционального объекта (заданного через параметр шаблона). Для shared_ptr пользовательский удалитель (как и счетчик ссылок, слабый счеткик, аллокатор и т.п.) является частью управляющего блока, выделенного в динамической памяти.
Поэтому:
- При копировании/перемещении умного указателя функция не копируется/перемещается. Копирование/перемещение умного указателя копирует/перемещает только указатель на эту функцию(функц. объект) или на управляющий блок.