我目前正在研究网络软件。它有一个主类server
,它显然代表一个服务器实例。
server
实例可以发送请求,并通过回调通知用户响应。
代码如下:
class server
{
public:
typedef boost::function<void (int duration)> callback_func;
void send_request(endpoint& ep, callback_func cb);
};
现在让我们说,作为一个用户,我希望回调知道调用它的实例,我可以做以下事情:
void mycallback(const server& sv, int duration) { ... }
server sv;
sv.send_request("localhost", boost::bind(&mycallback, boost::ref(sv), _1));
但我想知道:有没有这样做的开销?对mycallback
的呼叫是否比使用“常规”呼叫慢?
谢谢。
脚注:我当然可以将我的typedef
更改为:typedef boost::function<void (const server& sv, int duration)> callback_func;
,如果boost::bind
导致任何重大开销,那可能就是我最终要做的事情。我想知道使用boost::bind
。
答案 0 :(得分:5)
当然会导致开销。它的作用是创建一个存储绑定参数的仿函数,并使用剩余的参数调用operator()
。现在,这是重要的吗?我不知道,因为那只是一个字。提出1000万个请求并进行衡量。你是唯一可以判断这种开销是否对你很重要的人。
另外,我遇到了类似的问题。因为我不需要委托,所以我可以使用函数指针。但我发现了一个有趣的benchmark,它也提到了一些替代实现,所有这些实现都比boost::function
具有更好的性能。这是以可移植性为代价的,在某些情况下是实施中的丑陋,非标准的黑客攻击(但是回报非常好)。
答案 1 :(得分:5)
boost::bind
生成一个功能对象,如果它被用作函数模板的参数,可以对其进行优化,但是boost::function
会阻止这种优化,就像传递指向函数的指针一样会阻止其内联。 boost::function
本身不需要引入比虚函数更多的开销,也不需要通过函数指针调用。
PS。我同意TamásSzelei:提出1000万个请求并进行衡量。
答案 2 :(得分:2)
与普通函数调用相比,您为函数调用支付两个间接值,这类似于(非虚拟化)虚函数调用的开销。
第一个间接是由于boost :: function中发生的类型擦除(在boost::function
文档中这是documented)。这个不能真正优化,你也可以使用裸函数指针同样处罚。
第二个间接来自通过函数指针调用mycallback
函数。一个非常优化的编译器可以解决这个问题并优化它,但普通的编译器不会。如果将mycallback
转换为函数对象,则可以摆脱这种间接(在所有编译器中):
而不是
void mycallback( .1. ) { .2. }
你做了
struct mycallback {
void operator()( .1. ) const { .2. }
};
答案 3 :(得分:1)
请注意boost :: bind会导致仿函数的副本。这可能非常重要。对于我的操作系统,新闻和删除非常昂贵。请参阅关于ref()和cref()的boost :: bind文档。我相信成员函数也会导致仿函数副本,但没有相关的文档。