这可能是一个哲学问题,但我遇到了以下问题:
如果您定义了一个std :: function,并且没有正确初始化它,那么您的应用程序将崩溃,如下所示:
typedef std::function<void(void)> MyFunctionType;
MyFunctionType myFunction;
myFunction();
Run Code Online (Sandbox Code Playgroud)
如果函数作为参数传递,如下所示:
void DoSomething (MyFunctionType myFunction)
{
myFunction();
}
Run Code Online (Sandbox Code Playgroud)
然后,当然,它也崩溃了.这意味着我被迫添加这样的检查代码:
void DoSomething (MyFunctionType myFunction)
{
if (!myFunction) return;
myFunction();
}
Run Code Online (Sandbox Code Playgroud)
需要这些检查让我回到旧的C日,你还必须明确检查所有指针参数:
void DoSomething (Car *car, Person *person)
{
if (!car) return; // In real applications, this would be an assert of course
if (!person) return; // In real applications, this would be an assert of course
...
}
Run Code Online (Sandbox Code Playgroud)
幸运的是,我们可以在C++中使用引用,这阻止我编写这些检查(假设调用者没有将nullptr的内容传递给函数:
void DoSomething (Car &car, Person &person)
{
// I can assume that car and person are valid
}
Run Code Online (Sandbox Code Playgroud)
那么,为什么std :: function实例有一个默认的构造函数?如果没有默认构造函数,则不必添加检查,就像函数的其他正常参数一样.在那些你想要传递'可选'std :: function的'罕见'情况下,你仍然可以传递一个指向它的指针(或者使用boost :: optional).
Nic*_*las 15
没错,但其他类型也是如此.例如,如果我希望我的类有一个可选的Person,那么我将我的数据成员设为Person-pointer.为什么不对std :: functions做同样的事情?std :: function有什么特别之处,它可以有一个'无效'状态?
它没有"无效"状态.它不再无效:
std::vector<int> aVector;
aVector[0] = 5;
Run Code Online (Sandbox Code Playgroud)
你拥有的是空的 function,就像aVector是空的vector.对象处于非常明确的状态:没有数据的状态.
现在,让我们考虑一下你的"函数指针"建议:
void CallbackRegistrar(..., std::function<void()> *pFunc);
Run Code Online (Sandbox Code Playgroud)
你怎么称呼它?嗯,这是你不能做的一件事:
void CallbackFunc();
CallbackRegistrar(..., CallbackFunc);
Run Code Online (Sandbox Code Playgroud)
这是不允许的,因为它CallbackFunc是一个函数,而参数类型是a std::function<void()>*.这两个不可转换,所以编译器会抱怨.所以为了打电话,你必须这样做:
void CallbackFunc();
CallbackRegistrar(..., new std::function<void()>(CallbackFunc));
Run Code Online (Sandbox Code Playgroud)
你刚刚介绍new了图片.您已分配资源; 谁将负责呢?CallbackRegistrar?显然,您可能想要使用某种智能指针,因此您可以使用以下内容使界面更加混乱:
void CallbackRegistrar(..., std::shared_ptr<std::function<void()>> pFunc);
Run Code Online (Sandbox Code Playgroud)
这是一个很多API的烦恼和残酷,只是传递一个功能.避免这种情况的最简单方法是允许std::function为空.就像我们允许std::vector空洞一样.就像我们允许std::string空洞一样.就像我们允许std::shared_ptr空洞一样.等等.
简单地说:std::function 包含一个函数.它是可调用类型的持有者.因此,它可能不包含可调用类型.
实际上,您的应用程序不应该崩溃.
§20.8.11.1类bad_function_call [func.wrap.badcall]
1 /当函数包装器对象没有目标时
bad_function_call,function::operator()(20.8.11.2.4)抛出类型异常.
行为是完美的.
最常见的用例之一std::function是注册回调,在满足某些条件时调用.允许未初始化的实例可以仅在需要时注册回调,否则您将被迫始终至少传递某种无操作函数.
答案可能是历史的:std::function用作函数指针的替代品,函数指针有能力NULL.因此,当您希望提供与函数指针的轻松兼容性时,您需要提供无效状态.
可识别的无效状态并非真正必要,因为正如您所提到的boost::optional那样,这项工作就可以了.所以我会说那std::function是为了历史而存在的.
| 归档时间: |
|
| 查看次数: |
11867 次 |
| 最近记录: |