我正在尝试std::async
最终得到如下代码:
class obj {
public:
int val;
obj(int a) : val(a) {
cout << "new obj" << endl;
}
~obj() {
cout << "delete obj" << endl;
}
};
void foo(obj a) {
this_thread::sleep_for(chrono::milliseconds(500));
cout << a.val << endl;
}
int main(int argc, int **args) {
obj a(5);
auto future = async(foo, a);
future.wait();
return 0;
}
结果是:
new obj
delete obj
delete obj
delete obj
5
delete obj
delete obj
delete obj
然后我尝试改变void foo(obj a)
by void foo(obj &a)
:
new obj
delete obj
delete obj
delete obj
5
delete obj
delete obj
为什么要为这个简单的代码创建我的对象的 5 个副本?
我必须承认,我真的很困惑。有人愿意解释一下吗?
Edit
我用的是VS2012
就你而言,obj
正在复制:
- 两次通过电话std::async.
- 两次通过
async
的内部呼叫std::bind.
- 一旦接到电话
void foo(obj a)
因为它需要a
按价值。
不管你信不信,副本数量实际上已经自 VC10 以来减少.
看到一个库(无论是标准库还是另一个库)触发比您预期的类型更多的副本并不罕见。通常,您对此无能为力。
人们通常会做两件事来防止复制:
- Take
obj
通过引用(或者在您的情况下,const ref 因为foo
不修改obj
)。这将需要使用std::ref与异步。
- 定义一个移动构造函数 for
obj
。这不会阻止临时对象的构建和销毁,但它会给您一个稍微优化过程的机会。
请注意,在您仅持有一个对象的裸示例中int
,实际上复制可能比移动或通过引用传递更快。
通过示例obj
通过引用进入async
:
void foo(const obj& a) {
this_thread::sleep_for(chrono::milliseconds(500));
cout << a.val << endl;
}
int main(int argc, int **args) {
obj a(5);
auto future = async(foo, std::cref(a));
future.wait();
return 0;
}
定义移动构造函数的示例:
class obj
{
public:
/* ... */
obj(obj&& a) : val(move(a.val)) {
// It is good practice to 0 out the moved object to catch use-after-move bugs sooner.
a.val = 0;
}
/* ... */
};
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)