为啥 std::async 不能与接收抽象类引用作为参数的函数一起使用?
Posted
技术标签:
【中文标题】为啥 std::async 不能与接收抽象类引用作为参数的函数一起使用?【英文标题】:Why std::async cannot be used with functions that receive a reference to an abstract class as a parameter?为什么 std::async 不能与接收抽象类引用作为参数的函数一起使用? 【发布时间】:2019-07-07 18:23:10 【问题描述】:我正在尝试通过std::async
执行接收参数的函数,该参数是对抽象类的引用,但似乎由于某种原因这无效。另一方面,如果我用指针替换提到的引用,一切正常。
为什么会这样?将抽象类参数作为指针传递通常会更好吗?
请看下面的例子:
std::async 使用不正确
#include <iostream>
#include <future>
class AbsClass
public:
virtual int f() = 0;
;
class ImplClass : public AbsClass
public:
int f() override return 21;
;
int func(AbsClass &asbclass)
return 210 + asbclass.f();
int main()
ImplClass ic;
AbsClass &ac = ic;
// This causes a compilation failure:
std::future<int> res = std::async(&func, ac);
std::cout << res.get() << std::endl;
显示失败
/usr/include/c++/7/future:1745:5: error: invalid abstract parameter type ‘AbsClass’
main.cpp:4:7: note: because the following virtual functions are pure within ‘AbsClass’:
class AbsClass
^~~~~~~~
main.cpp:6:17: note: virtual int AbsClass::f()
virtual int f() = 0;
正确使用 std::async
#include <iostream>
#include <future>
class AbsClass
public:
virtual int f() = 0;
;
class ImplClass : public AbsClass
public:
int f() override return 21;
;
int func(AbsClass *asbclass)
return 210 + asbclass->f();
int main()
ImplClass ic;
AbsClass &ac = ic;
std::future<int> res = std::async(&func, &ac);
std::cout << res.get() << std::endl;
【问题讨论】:
【参考方案1】:需要存储参数,这意味着它们被复制。并且引用不能被复制。
因此引入了reference wrapper,它可以存储引用同时也可以被复制。您可以将其与辅助函数 std::ref
and std::cref
一起使用:
std::future<int> res = std::async(&func, std::ref(ac)); // Pass ac by reference
【讨论】:
值得注意的是,由于无法实例化抽象类,因此复制失败。如果它不是一个抽象类,程序会编译,但你会面临Object Slicing同样不吸引人的问题。 有趣的旁注:指针也会发生完全相同的事情。指针被复制,但由于您不关心是否有原始指针(尽管有时您有),所以您不会注意到副本。 如何知道参数需要存储?我无法在 std::async 文档中阅读。当你说引用不能被复制时,你是什么意思?我既可以复制引用指向的地址,也可以复制它指向的实际值,对吧? @Dan 未指定何时调用该函数。可以立即调用它,也可以在稍后的任何时间点调用get
返回的未来。因此必须存储函数的参数。
@Dan async
没有在这个话题上说太多,但async
使用了thread
和thread
对此进行了警告。以下是 CPP 参考中the notes 针对std::thread
的构造函数的简要讨论: 线程函数的参数按值移动或复制。如果需要将引用参数传递给线程函数,则必须对其进行包装(例如,使用std::ref
或std::cref
。以上是关于为啥 std::async 不能与接收抽象类引用作为参数的函数一起使用?的主要内容,如果未能解决你的问题,请参考以下文章
为啥 std::future 从 std::packaged_task 和 std::async 返回不同?