我有一个程序,可以在收到消息时从库接收回调调用。回调的签名是
void on_message(const MyLargeObject &my_large_object);
我对某些消息做出反应的代码比我想直接在回调中运行的代码更复杂。因此,我正在启动一个异步任务(std::async)来进行实际处理。
目前,异步任务的签名是
void on_message_async_task(MyLargeObject my_large_object);
。我的推理是,我应该将参数作为副本传递给异步任务,因为我认为无法保证原始对象在任务完成之前一直存在。然而,静态代码分析表明我应该使用 const 引用来避免昂贵的复制。这是误报还是我在这里遗漏了一些东西?
任务函子通过引用接受对象似乎是一个合理的建议。请注意,这并不意味着任务的共享状态应该存储对库回调中的对象的引用。任务应该创建一个副本,以便它能够存活足够长的时间,但是仿函数应该接受引用,以避免在调用它时出现另一个副本。
#include <future>
#include <iostream>
struct Object
{
Object() { ::std::cout << static_cast<void*>(this) << " Object{}\n"; }
Object(Object const &) { ::std::cout << static_cast<void*>(this) << " Object{copy}\n"; }
~Object() { ::std::cout << static_cast<void*>(this) << " ~Object\n"; }
void operator =(Object const &) { ::std::cout << static_cast<void*>(this) << " ={copy}\n"; }
};
void ByRef(Object const &) { ::std::cout << "ByRef\n"; }
void ByCopy(Object const) { ::std::cout << "ByCopy\n"; }
void Callback(Object const & object)
{
::std::cout << "ByRef Start\n";
::std::async(::std::launch::async, ByRef, object).get();
::std::cout << "ByCopy Start\n";
::std::async(::std::launch::async, ByCopy, object).get();
}
int main()
{
Object object{};
Callback(object);
::std::cout << "Done\n";
return 0;
}
0x7ffeda17c69f 对象{} 通过引用开始 0x456308 对象{副本} 通过引用 0x456308 ~对象 通过复制开始 0x456308 对象{副本} 0x70be36ffe89f 对象{复制} 通过复制 0x70be36ffe89f ~对象 0x456308 ~对象 完毕 0x7ffeda17c69f ~对象