在线程中运行lambda时如何减少副本?

时间:2018-07-16 18:46:21

标签: c++ multithreading lambda

我正在尝试将lambda与c ++中的线程一起使用,并使用捕获作为将数据传递到线程的一种方式。创建线程后,以下代码将打印“ ConnectionInfo(copy)”三次。是否有将其缩小为单个副本的方法?我不确定为什么要额外复制两次。

#include <iostream>
#include <functional>
#include <memory>
#include <thread>

using namespace std;

class ConnectionInfo
{
public:
    ConnectionInfo():port(0) {}
    ConnectionInfo(int p):port(p) {}
    ConnectionInfo(const ConnectionInfo &other) 
    {
        std::cout << "ConnectionInfo(copy)" << std::endl;
        port = other.port;
    }

    int port;
    void Connect() {};

};


int main() {

    std::cout << "Create" << std::endl;
    ConnectionInfo c(2);


    std::cout << "Thread" << std::endl;
    std::thread t(
    [a = c]() mutable
    { 
        a.Connect();
        std::cout << "Done" << std::endl;
    }
    );

    std::cout << "Joining" << std::endl;
    t.join();
    std::cout << "Joined" << std::endl;

    return 0;
}

输出为:

Create
Thread
ConnectionInfo(copy)
ConnectionInfo(copy)
ConnectionInfo(copy)
Joining
Done
Joined

1 个答案:

答案 0 :(得分:2)

std :: thread的定义要求将参数按值传递给新线程,并且lambda在您的情况下是临时的,这正是您想要的。但是,这些多余的副本实际上很可能会降级为副本,因为您的类没有move构造函数。

因此,在类中添加一个move构造函数,应将序列简化为一个副本(捕获)和两个move。

当然,这仅在移动比复制便宜的情况下才有用,但是如果复制的开销与线程的创建相比很重要,则您的对象很可能在堆上管理某些数据或必须执行其他操作昂贵的复制操作通常可以在move构造函数中省略。