C ++ 11线程编译错误,删除了复制构造函数和std :: thread,为什么?

时间:2014-03-27 11:43:36

标签: c++ c++11

这会发出大约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;
}

2 个答案:

答案 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();
    }
};