这会发出大约100行错误。错误:使用run_me复制构造函数的已删除函数等。 那么,这里的问题是什么?
#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;
}
答案 0 :(得分:5)
您的ifstream
实施不支持移动操作,仍然会删除复制操作。
您可以使用lambda来延迟线程内的run_me创建
std::thread t { [] { run_me{}(); } };
如果您想在线程开始之前保留run_me创建,可以使用std::ref
run_me rm;
thread t1{ []( run_me & rm ) { rm(); }, std::ref(rm) };
答案 1 :(得分:4)
说明
标准要求传递给std::thread
的相关构造函数的对象和参数必须为MoveConstructible
。
给定代码的问题是class run_me
具有隐式已删除的复制/移动构造函数,因为它具有不可复制的成员; std::ifstream fs
。
解决方案#1 - 更改来电网站
为了防止编译器尝试复制class run_me
,我们要做的就是将对象包装在lambda中并用这个对象初始化std::thread
:
std::thread t1 {
[] { run_me {} (); }
};
注意:以上创建了一个临时run_me {}
并在匿名lambda内调用operator()
,临时run me {}
将在创建时创建实际上调用lambdas函数,而不是在创建lambda时调用。当t1
调用anonymous-lambda ()
时,系统会输入功能范围,并初始化run_me {}
。
解决方案#2 - 更改class run me
通常情况下,我们只需将 move-constructor 添加到class run_me
,该fs
会使用原始std::move
的{{1}} d实例初始化fs
,这不是一个大问题。
遗憾的是libstdc++
hasn't implemented the functionality required to properly move streams这样的实现,这意味着我们无法移动标准库流。
如果您正在使用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();
}
};