如何在不复制列表的情况下将列表传递给线程,同时破坏原始列表

How to pass a list to a thread without copying it, while destroying the original

此代码创建并执行一个线程,该线程需要获取 std::list<int> data 的内容,而无需复制此列表的内容并将其地址更改为内存。指向列表的指针必须对其他代码保持有效。

创建线程后,原来的列表data在主线程中被销毁,所以在这种情况下我不能使用它的地址。

我怎样才能做到这一点?我尝试过使用右值引用,但我担心如果我以这种方式尝试,我可能会有一个悬空指针。这是我拥有的:

void func(std::list<int> && data){  // <-- what should go here as an argument?
   std::sort(data.begin(), data.end());
   // do stuff with data
}

int main(){
    {
        std::list<int> data;
        data.push_back(1);
        std::thread(func, std::move(data)).detach();
    } 
    // data destroyed
}

thread 的构造函数调用

std::invoke(decay_copy(std::forward<Function>(f)), 
            decay_copy(std::forward<Args>(args))...);

其中decay_copy定义如下:

template <class T>
std::decay_t<T> decay_copy(T&& v) { return std::forward<T>(v); }

你超过了move(data)。因为decay_copy使用了引用转发,所以returnsT&&,因为decay_t丢弃了constness和referenceness,新的列表对象是使用移动构造函数创建的。因此 main 中的 data 列表被移动到线程构造函数中(thread 将其参数存储在元组中 - 您不需要关心移动数据列表对象的生命周期。现在,问题是您想要pass/access 移动 func 中的 data 列表的方式。通过 copy/move 或参考,详情如下)。

现在invoke被称为:

invoke (func, temporary list object returned by decay_copy)

这里有两种情况需要考虑:

[1] func 具有签名 func(list<int>&&),在这种情况下,您只是通过引用访问移动的列表对象 - 没有复制,也没有调用移动操作。

[2] func 具有签名 func(list<int>),在这种情况下,将在列表上调用移动构造函数。如果列表没有移动支持,复制操作将在这里调用。

所以使用list<int>&&,你将节省一次移动操作。