Верно, но это также верно для других типов.Например, если я хочу, чтобы в моем классе был необязательный объект Person, я делаю свой член данных указателем Person.Почему бы не сделать то же самое для std :: functions?Что такого особенного в std :: function, что оно может иметь состояние «недопустимо»?
У него нет состояния «недопустимо».Это не более недействительно, чем это:
std::vector<int> aVector;
aVector[0] = 5;
У вас есть пусто function
, точно так же, как aVector
- это пусто vector
.Объект находится в очень четко определенном состоянии: состояние отсутствия данных.
Теперь давайте рассмотрим ваше предложение «указатель на функцию»:
void CallbackRegistrar(..., std::function<void()> *pFunc);
Как вам нужноназывать это?Ну, вот одна вещь, которую вы не можете сделать:
void CallbackFunc();
CallbackRegistrar(..., CallbackFunc);
Это недопустимо, потому что CallbackFunc
- это функция, а тип параметра - std::function<void()>*
.Эти два не конвертируемы, поэтому компилятор будет жаловаться.Таким образом, чтобы сделать звонок, вы должны сделать это:
void CallbackFunc();
CallbackRegistrar(..., new std::function<void()>(CallbackFunc));
Вы только что ввели new
в изображение.Вы выделили ресурс;кто будет нести ответственность за это?CallbackRegistrar
?Очевидно, что вы можете захотеть использовать какой-нибудь умный указатель, поэтому вы еще больше загромождаете интерфейс с помощью:
void CallbackRegistrar(..., std::shared_ptr<std::function<void()>> pFunc);
Это очень раздражает и раздражает API, просто чтобы передать функцию.Самый простой способ избежать этого - разрешить std::function
быть пустым .Также как мы позволяем std::vector
быть пустым.Также как мы позволяем std::string
быть пустым.Также как мы позволяем std::shared_ptr
быть пустым.И так далее.
Проще говоря: std::function
содержит функцию.Это держатель для вызываемого типа.Следовательно, существует вероятность, что он не содержит вызываемого типа.