Передача статического оператора() как типа удаления
Законен ли следующий фрагмент кода в C++23?
#include <memory>
#include <cstdio>
int main()
{
struct custom_deleter
{
static void operator()(int* const ptr)
{
delete ptr;
std::fputs( "Deleted\n", stdout );
}
};
auto ptr { std::unique_ptr<int, decltype(&custom_deleter::operator())> {new int {5},
custom_deleter::operator()} };
}
GCC, кажется, в порядке с этим. Однако мне интересно, соответствует ли он стандартам.
Кроме того, почему удаление&
отdecltype(&custom_deleter::operator())
вызвать ошибку компиляции? Означает ли это, чтоDeleter
Параметр шаблона типа должен быть типом указателя функции (в данном случаеvoid(*)(int*)
)?
1 ответ
Это совершенно справедливо.static operator()
— это новая функция языка C++23, и вы используете ее правильно.
Однако, если вы действительно не хотите использовать средство удаления указателя функции (потому что... возможно, в какой-то момент вы захотите поменять другой указатель функции, и вам нужна такая гибкость), вам действительно следует оставить там весь тип:
std::unique_ptr<int, custom_deleter>
Это позволит оптимизировать гораздо лучше:
- если напишешь напрямую, то просто увидишь вызов
operator delete
, а другая версия простоcall [QWORD PTR [rax]]
, потому что это может быть что угодно - Также из-за
custom_deleter
пустой тип,sizeof(unique_ptr<int, custom_deleter>)
просто8
-sizeof(int*)
. Но размещение там указателя функции увеличивает размер до 16.
Кроме того, почему удаление from вызывает ошибку компиляции? Означает ли это, что параметр шаблона типа Deleter должен быть типом указателя функции?
Потому чтоdecltype(&custom_deleter::operator())
являетсяvoid(*)(int*)
- это указатель на функцию. Ноdecltype(custom_deleter::operator())
простоvoid(int*)
. Это тип функции.
В частности, это не обязательно должен быть тип указателя на функцию (во всяком случае, вам действительно следует избегать использования типов указателей на функции, если вам действительно не нужна такая гибкость), ноunique_ptr<T, Deleter>
имеет член типа, поэтомуDeleter
лучше бы это был тип, для которого вы можете иметь нестатический член данных - это работает для указателей функций и объектов функций, но не для простых функций. Вот почему&
необходимо.
Наконец, я просто хочу прокомментировать этот стиль:
auto var { Type { ... } };
Пожалуйста, просто напишите:
auto var = Type { ... };
Для объявлений, в которых вы просто объявляете переменную с явным типом, такого как этот, в любом случае нет никакой разницы. Эти двое означают одно и то же. Я понятия не имею, почему этот синтаксис вообще поддерживается (auto x{1, 2, 3};
в любом случае недействительно, вам придется написатьauto x = {1, 2, 3};
если ты хочешьstd::initializer_list<int>
). Всегда использую=
означает, что все ваши объявления переменных выглядят одинаково, включая те, которые инициализируются вызовами функций и т. д., и избавляет вас от дополнительного вложения фигурных скобок, что усложняет анализ остальных (для людей компилятор с этим справляется).