WFServer类构造时std::function传参问题
mallocnew opened this issue · comments
WFServer类构造的时候std::function<void (WFNetworkTask<REQ, RESP> *)> proc是以拷贝的方式传参进来的,process(std::move(proc))进行了一次移动来转移所有权,转移了proc的所有权。
这样依旧发生了一次拷贝构造(用户传参进行WFServer构造的时候)。
可以使用完美转发来传参?这样的话就减少了一次拷贝构造
WFServer(const struct WFServerParams *params,
std::function<void (WFNetworkTask<REQ, RESP> *)>&& proc) :
WFServerBase(params),
process{std::forward<std::function<void (WFNetworkTask<REQ, RESP> *)>>(proc)}
{
}
感谢建议。有几个问题。
- 为了减少用户理解和使用复杂性,我们用户接口上不使用右值。
- 目前的接口,也支持用户传入右值。和你这个写法性能上几乎没区别,甚至编译器优化之后可能完全相同。
- Server只构造一次,性能无所谓。传给Server task时是引用传递。
- 我们尽可能减少C++高级特征的使用。虽然forward也没多高级。
std::forward
是个高级特性,以至于很容易被人错误地理解,例如您的示例代码便是对其常见的误用。
通常来说,完美转发应结合引用折叠来使用,若要使用该特性,WFServer
的构造应改为
template<typename Proc>
WFServer(const struct WFServerParams *params, Proc&& proc)
: WFServerBase(params),
process{std::forward<Proc>(proc)}
{
}
这在构造函数上引入了模板参数,此处忽略更深入的讨论。
从使用者的角度看,通常有两种创建WFServer
实例的方式,
// 1. proc较为复杂,先构建proc
auto proc = [&some_global_var](WFXXXTask *) { /* do someting with very long code */ };
// or
auto proc = std::bind(real_proc, /* some very long args that you don't want to write in servers construct */, _1, /* some args */);
// or
const auto &proc = create_processor(/*very very very complicated args used to create a processor instance */);
WFXXXServer server(params, proc);
// 2. proc较为简单,直接用来构建server
void process(WFXXXTask *);
void process_with_ctx(Context *, WFXXXTask *);
struct Processor {
void operator(WFXXXTask *);
};
WFXXXServer server(params, process);
WFXXXServer server(params, [ctx](WFXXXTask *task) mutable { process_with_ctx(ctx, task); });
WFXXXServer server(params, Processor{});
从设计者角度看,需要同时可以处理参数是T &
, const T &
,以及T &&
的情况(另可能有const T &&
可规约到const T &
),此时该构造函数需要下述两种格式
WFServer(const struct WFServerParams *params,
std::function<void (WFNetworkTask<REQ, RESP> *)>&& proc) :
WFServerBase(params),
process{std::move(proc)}
{
}
以及
WFServer(const struct WFServerParams *params,
const std::function<void (WFNetworkTask<REQ, RESP> *)>& proc) :
WFServerBase(params),
process{proc}
{
}
其中,const std::function<...> &
可用来处理std::function<...> &
和const std::function<...> &
两种情况。
也就是说,要想完美地解决问题,可以选择使用1. 模板函数
或者2. 重载多个函数
,而如果需要一个不那么完美的、可以少写代码的方法,则使用目前WFServer中使用的,以std::function<...>
为参数的风格。