使用rvalue-references进行异步回调

时间:2017-03-20 19:09:23

标签: c++ multithreading asynchronous callback rvalue-reference

我正在研究一种可以执行某种科学计算的库。 它旨在与GUI一起使用,因此计算是异步执行的,GUI(或任何将任务排入lib中的任何内容)将在先前指定的std::function上接收回调。 那些回调应始终收到一个小的状态响应对象,即

struct StatusResponse {
    StatusResponse(int respC, std::string respS): responseCode(respC), 
    responseString(std::move(respS)) {};
    int responseCode;
    std::string responseString;
};

这些回调是即发即弃的,它们不会返回任何内容(无效),也不需要等待回调执行的其他操作。 因此,StatusResponse对象也是临时的。 现在似乎有多种方法可以解决。 我的第一个想法是定义回调函数如下

    template<typename T0>
using Action = std::function<void(std::shared_ptr<T0>)>;

将其称为

rdt::Action<rdt::StatusResponse> callback;

std::shared_ptr<rdt::StatusResponse> response = 
std::make_shared<rdt::StatusResponse>
(rdt::errorcode::DEVICE_ID_OUT_OF_RANGE, std::string {"Device ID out 
of Range!"});

callback(response);
return;

这看起来非常低效且成本高昂(使用std::shared_ptr进行即发即弃,此外程序需要返回库函数,只是为了返回......) 现在我做了另一种方式:

void callback(std::unique_ptr<StatusResponse> response);

std::unique_ptr<StatusResponse> response = 
std::make_unique<StatusResponse>(0, "success!");

callback(std::move(response));

然而,这似乎仍然无效,因为我正在围绕一个将被销毁的对象构建一个包装器。

void callback(StatusResponse&& response);

StatusResponse response {0, "Success!"};
callback(std::move(response));

是可能的,甚至是

callback(StatusResponse {0, "Success!"});

所以,现在,我对这些可能性非常不确定。

第一个问题:结构中的std::move是否合适?

第二个问题:哪种解决方案能提供最佳的速度优势?回调可能会被称为

std::thread t(callback, StatusResponse {0, "Success!"});
t.detach();

我刚开始学习rvalue-references和智能指针,所以非常感谢任何帮助!

编辑: 我进行了一次测试,SergeyA似乎是正确的。 右值参考方式产生以下调试输出:

Constructor Called!
Copy Constructor Called!
Copy Constructor Called!
Destructor Called!
Destructor Called!
Callback called!
Called callback!
Exiting caller!
Exiting callback!
Destructor Called!

提供移动构造函数会导致Copy Constructor Called替换为Move Constructor Called

1 个答案:

答案 0 :(得分:0)

不,右值引用不正常 - 语句完成后将删除临时值。实际上,最有效的方法是按值复制,但在结构上使用移动构造函数,并从临时或std::move()结果创建它。