C++ C++;11线程编译错误,删除了复制构造函数和std::thread,为什么?
这会发出大约100行错误。错误:使用了run_me copy构造函数的deleted函数等。 那么,这里有什么问题C++ C++;11线程编译错误,删除了复制构造函数和std::thread,为什么?,c++,c++11,C++,C++11,这会发出大约100行错误。错误:使用了run_me copy构造函数的deleted函数等。 那么,这里有什么问题 #include<thread> #include<iostream> #include<vector> #include<fstream> #include<string> #include<chrono> using namespace std; //creating thread to print l
#include<thread>
#include<iostream>
#include<vector>
#include<fstream>
#include<string>
#include<chrono>
using namespace std;
//creating thread to print line from file
class run_me {
ifstream fs;
public:
string s;
run_me(): fs("lliftOff.cpp",ifstream::in) {}
void operator()(){
cout<<"hi";
while(getline(fs,s) ) {
cout<<s<<endl;
this_thread::sleep_for (chrono::seconds(1));
}
}
~run_me() {
fs.close();
}
};
int main() {
thread t1{run_me()};
t1.join();
cout<<"shutting down now"<<endl;
}
#包括
#包括
#包括
#包括
#包括
#包括
使用名称空间std;
//创建从文件打印行的线程
班主任{
IFFS;
公众:
字符串s;
运行_me():fs(“lliftOff.cpp”,ifstream::in){}
void运算符()(){
cout您的ifstream
实现缺少对移动操作的支持,仍在删除复制操作
您可以使用lambda延迟线程内的run\u me创建
std::thread t { [] { run_me{}(); } };
如果希望在线程开始之前保持运行创建,可以使用std::ref
run_me rm;
thread t1{ []( run_me & rm ) { rm(); }, std::ref(rm) };
解释
标准要求传递给std::thread
的相关构造函数的对象和参数必须是MoveConstructible
给定代码的问题是类run\u me
有一个隐式删除的复制/移动构造函数,因为它有一个不可复制的成员;std::ifstream fs
解决方案#1-更改通话地点
为了防止编译器试图复制类run_me
,我们所要做的就是将对象包装在lambda中,并使用所述对象初始化std::thread
:
std::thread t1 {
[] { run_me {} (); }
};
注意:上面创建了一个临时的run_me{}
并在匿名lambda内部对其调用operator()
,临时的run me{}
将在实际调用lambda函数时创建,而不是在创建lambda时。当t1
调用匿名lambda()
将输入功能范围,并初始化运行{}
解决方案#2-更改类运行我
通常我们只需向类run\u me
添加一个move构造函数,该构造函数将使用原始fs
的std::move
d实例初始化fs
,这并不是什么大问题
不幸的是,像libstdc++
这样的实现意味着我们还不能移动标准库流
如果您使用的是libstdc++
,或者任何其他缺少移动流的实现,那么在编写解决方案时,我们将不得不求助于某种黑客手段,我建议您:
#include <iostream>
#include <fstream>
#include <string>
#include <memory>
class run_me {
std::unique_ptr<std::ifstream> fs;
public:
string s;
run_me()
: fs (new std::ifstream ("foo.cpp",ifstream::in))
{ }
run_me (run_me&& src)
: fs (std::move (src.fs))
{ }
void operator()() {
while(getline(*fs,s) ) {
cout<<s<<endl;
this_thread::sleep_for (chrono::seconds(1));
}
}
~run_me() {
if (fs) // if we haven't been moved-from
fs->close();
}
};
#包括
#包括
#包括
#包括
班主任{
std::唯一的ptr fs;
公众:
字符串s;
快跑
:fs(新的std::ifstream(“foo.cpp”,ifstream::in))
{ }
run_me(run_me&&src)
:fs(标准::移动(src.fs))
{ }
void运算符()(){
while(getline(*fs,s)){
coutFile streams会自动关闭。不需要析构函数。istream不可复制。因此我猜默认的复制构造函数正在尝试复制ifstream。有一个输入错误,它是libstdc++
notstdlibc++
@user2485710。修复了,供将来参考,您可以通过编辑有问题的帖子来自己修复此类输入错误。有人知道吗请详细说明如何使用lambda函数延迟创建对象。它是如何工作的?std::thread t1{[]{run_me{}();};@vivek请参阅解决方案#1中的修改注释。@vivek它相当于run_me temporary_variable={};temporary_variable()
,即:首先默认初始化一个临时的运行me
,然后在此临时对象上调用操作符()
。我认为您实际上不需要解决方案中的lambda。如果包装对象是可调用的,则“std::ref”返回的“std::reference包装器”已可调用。