为何不始终采用右值引用作为C++ API的参数?
回调API的参数传递设计:右值引用 vs 按值传递
问题背景
我维护着一个API,功能是将订阅项加入存储std::function的vector中。由于std::function可能涉及堆内存分配,对其执行move操作是合理且高效的。目前这个API有两种实现方式:
- 按值传递参数
- 按右值引用传递参数
场景分析
在实际使用中,用户传入lambda(右值)的概率极高:
- 若采用按值传递,函数体内会额外触发一次
std::function的move构造,这属于不必要的性能开销; - 若采用右值引用传递,虽然要求用户传入右值,但如果用户需要将同一个函数对象分发到多个接收端,只需在调用API前自行拷贝对象即可。
核心疑问
既然如此,为什么不始终选择第二种设计——用右值引用作为参数,让调用者自行处理拷贝操作?这种设计不会给用户带来额外负担:仅在需要复用对象时提前拷贝,其他场景下用户完全能掌控API的行为,还能避免move构造带来的性能损耗。
示例代码
#include <functional> #include <cstdio> #include <vector> struct entity { auto on_change(std::function<void()>&& cb) { callbacks_.push_back(std::move(cb)); } auto print_all() { std::for_each(callbacks_.cbegin(), callbacks_.cend(), [](const auto& cb){ cb(); }); } std::vector<std::function<void()>> callbacks_; }; auto foo() -> void { printf("Hello from function!\n"); } int main() { entity e,d; // 常规场景:直接传入右值lambda e.on_change([](){ printf("Hello from lambda!\n"); }); // 特殊场景:需要复用同一个函数对象 auto fn = std::function<void()>([]{ printf("Hello from function that gets distributed multiple times!\n"); }); // 以下两行无法编译,因为fn是左值 // e.on_change(fn); // d.on_change(fn); // 可通过以下方式处理: e.on_change(std::function<void()>(fn)); // 显式拷贝新的function对象 d.on_change(std::move(fn)); // 转移fn的所有权给d的回调列表 e.print_all(); d.print_all(); }
程序输出
Hello from lambda! Hello from function that gets distributed multiple times! Hello from function that gets distributed multiple times!
内容的提问来源于stack exchange,提问作者glades
相关产品推荐
相关产品推荐

