如何在不复制列表的情况下将列表传递给线程,同时破坏原始列表
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>&&
,你将节省一次移动操作。
此代码创建并执行一个线程,该线程需要获取 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>&&
,你将节省一次移动操作。