You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用std::async调用成员函数时,传对象与对象指针为何效果不同?

std::async调用成员函数时传参导致拷贝的问题解答

问题场景

学习C并发编程时,遇到《C Concurrency in Action, 2nd Edition》4.2.1节代码清单4.7中的情况:使用std::async调用成员函数时,传对象指针不会拷贝原对象,直接传对象则会触发拷贝。

代码示例:

//Listing 4.7 Passing arguments to a function with std::async

#include <string>
#include <future>
struct X
{
 void foo(int,std::string const&);
 std::string bar(std::string const&);
};
X x;
auto f1=std::async(&X::foo,&x,42,"hello"); //Calls p->foo(42,"hello"), where p is &x
auto f2=std::async(&X::bar,x,"goodbye");   //Calls tmpx.bar("goodbye"), where tmpx is a copy of x

疑问:两种传参方式为何产生不同结果?是否和右值有关?


解答

1. 成员函数的底层调用逻辑

非静态成员函数在编译时会被隐式添加第一个参数——指向类对象的this指针。也就是说,X::foo的实际签名等价于:

void foo(X* this, int, std::string const&);

调用成员函数时,必须为this指针绑定一个有效类实例的地址。

2. 传指针的情况(f1)

传递&x给std::async时,这个指针直接被绑定到成员函数的this参数上,最终执行的是(&x)->foo(42, "hello"),全程直接操作原对象x,没有拷贝行为。

3. 传对象的情况(f2)

直接传递x(左值对象)时,std::async的参数默认是按值传递的。它会先拷贝一份x到内部的临时存储(即书中的tmpx),然后用这个临时对象的地址作为this指针调用bar函数。这就是产生拷贝的核心原因——参数按值传递的规则,和右值没有直接关系。

如果传递的是右值(比如std::move(x)),std::async会用移动构造创建临时对象,而非拷贝构造,但本质还是会生成新对象,原对象的状态会被转移,同样不会直接操作原对象。

4. 如何避免拷贝操作

如果想直接操作原对象但不想传指针,可以用std::ref或std::cref包装对象,让std::async传递引用而非值:

auto f2 = std::async(&X::bar, std::ref(x), "goodbye"); // 直接操作原x,无拷贝

内容的提问来源于stack exchange,提问作者soyokaze

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 12:42:24