std::shared_future按引用传入函数是否合法?如何选择传参方式?
按值传递的合法性
按值传递std::shared_future是合法行为,因为std::shared_future本身支持拷贝操作,示例代码如下:
#include <future> #include <vector> #include <iostream> int factorial(std::shared_future<int> sf) { int res = 1; int num = sf.get(); for(int i=num; i>1; i--) { res *= i; } return res; } int main() { std::promise<int> prs; std::vector<std::future<int>> vec; std::shared_future<int> sf{prs.get_future()}; for(int i=0; i<10; i++) { vec.push_back(std::async(std::launch::async, factorial, sf)); } prs.set_value(5); for(auto& fut: vec) { std::cout << fut.get() << std::endl; } }
引用传递的合法性验证
将std::shared_future以引用形式传入函数的示例代码如下:
#include <future> #include <vector> #include <iostream> int factorial(std::shared_future<int>& sf) { int res = 1; int num = sf.get(); for(int i=num; i>1; i--) { res *= i; } return res; } int main() { std::promise<int> prs; std::vector<std::future<int>> vec; std::shared_future<int> sf{prs.get_future()}; for(int i=0; i<10; i++) { vec.push_back(std::async(std::launch::async, factorial, std::ref(sf))); } prs.set_value(5); for(auto& fut: vec) { std::cout << fut.get() << std::endl; } }
上述代码片段可正常编译,且看起来运行效果正常。
核心结论
引用传递的合法性前提
上述引用传递代码能正常运行,需要同时满足两个条件:- 被引用的
std::shared_future对象生命周期覆盖所有异步任务的执行全程:示例中sf定义在main函数栈上,主线程通过循环调用fut.get()阻塞等待所有任务执行完成后才会退出,sf不会在任务运行期间被销毁。 - 不存在并发修改:
std::shared_future::get()是线程安全的const成员函数,多个线程同时调用不会产生数据竞争。
但这种写法存在明确的安全隐患:如果被引用的shared_future提前销毁,异步任务访问悬空引用会触发未定义行为。
- 被引用的
传参方式选择规则
和std::shared_ptr的传参逻辑一致,两种方式没有绝对对错,需要结合场景选择:- 跨线程、异步场景优先选择按值传递:每个持有拷贝的执行单元自行管理共享状态的生命周期,从根源上避免悬空引用风险。
shared_future的拷贝仅会增加内部共享状态的引用计数,开销极低,是这类场景下最稳妥的选择。 - 同一作用域内的同步调用可以使用引用传递:如果能100%保证原
shared_future对象的生命周期覆盖被调用方的全部使用流程,按引用传递可以省去一次引用计数增减的微小开销,不存在安全问题。 - 无生命周期保障的场景禁止使用引用传递:这类场景下悬空引用的风险,远大于引用计数操作带来的微小性能收益。
- 跨线程、异步场景优先选择按值传递:每个持有拷贝的执行单元自行管理共享状态的生命周期,从根源上避免悬空引用风险。
内容的提问来源于stack exchange,提问作者John
相关产品推荐
相关产品推荐

