2014-03-27 51 views
2

這會發出大約100行錯誤。錯誤:使用run_me複製構造函數的已刪除函數等。 那麼,這裏有什麼問題?C++ 11線程編譯錯誤,刪除拷貝構造函數和std :: thread,爲什麼?

#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; 
} 
+1

文件流關閉他們自己。不需要析構函數。 – chris

+0

istream不可複製。所以我猜測默認的拷貝構造函數試圖複製ifstream。 – anonymous

回答

4

THE說明

該標準規定對象和參數傳遞給rel std::thread的前期構造函數必須是MoveConstructible

具有給定代碼的問題是,class run_me具有隱含刪除複製/移動構造函數,因爲它具有一個不可複製件; std::ifstream fs


解決方案#1 - 更改呼叫現場

爲了防止編譯器試圖複製class run_me所有我們所要做的就是包裝拉姆達內的對象,並使用此說對象初始化我們std::thread

std::thread t1 { 
    [] { run_me {}(); } 
}; 

注:上面創建一個臨時run_me {}和Ca lls operator()在一個匿名lambda裏面,當lambda函數實際被調用時,臨時run me {}將被創建,而不是在創建lambda時。當t1調用anonymous-lambda()時,將輸入功能範圍,並且run_me {}將被初始化。


SOLUTION#2 - CHANGE class run me

通常情況下,我們想補充一個移動構造函數class run_me將初始化fs與原fsstd::move d實例,而不是一個真正的大事件。

令人傷心的實現,如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(); 
    } 
}; 
+0

有一個錯字,這是'的libstdC++''不++ stdlibc' – user2485710

+0

@ user2485710固定,以供將來參考您可以通過編輯相關的帖子自行修復這樣的錯別字。 –

+0

有人可以請詳細說明使用lambda函數來延遲創建對象。它是如何工作的? std :: thread t1 { [] {run_me {}(); } }; – claudius

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) }; 
+0

我不認爲你真的需要你的解決方案中的lambda。如果包裝的對象是可調用的,則'std :: ref'返回的'std :: reference_wrapper'已經可以調用。 – John5342