2013-12-21 173 views
7

我在嘗試創建使用C++ 11標準的VC++靜態庫時遇到問題線程。錯誤C2280:'std :: thread :: thread(const std :: thread&)':嘗試引用已刪除的函數

我目前有兩個類,我能夠聲明和稍後定義一個線程就好了我的起始類(這是宣佈最後)。在這個階段,代碼只是一個套接字偵聽器,然後創建另一個類的對象來處理接受的每個客戶端。這些子對象應該創建並行數據捕獲,編碼和傳輸所需的線程。

的問題是:如果我宣佈一個std ::線程我的其他類,即使完全像我做我的啓動類,不管是什麼,我得到關於構建這個錯誤error C2280: 'std::thread::thread(const std::thread &)' : attempting to reference a deleted function [...]\vc\include\functional 1124 1

的唯一的辦法,我能夠解決這個錯誤是根本沒有聲明std::thread對象在後一類,這是不可能的,根據我想要它做什麼...

我使用VS2013,並且我的來源是:

stdafx.h

#pragma once 
#include "targetver.h" 
#define WIN32_LEAN_AND_MEAN    // Exclude rarely-used stuff from Windows headers 
#include <Windows.h> 
#include <WinSock2.h> 
#include <WS2tcpip.h> 
#include <thread> 
#include <iostream> 
#include <vector> 

StreamServer.h

#pragma once 
#define DEFAULT_BUFLEN 65535 
#define DEFAULT_PORT "5649" 

class StreamServerClient 
{ 
public: 
    bool* terminate; 
    //std::thread client;  //If I comment this line out, it builds just fine. 
    void DoNothing(); 
    StreamServerClient(SOCKET clientSock, bool* ptTerm); 
    StreamServerClient(); 
    ~StreamServerClient(); 
}; 

class StreamServer 
{ 
public: 
    bool terminate; 
    std::thread Listener; 
    std::vector<StreamServerClient> clients; 
    void CreateClient(SOCKET, bool*); 
    void Listen(); 
    StreamServer(); 
    ~StreamServer(); 
}; 

StreamServer.cpp

#include "stdafx.h" 
#include "StreamServer.h" 

StreamServerClient::StreamServerClient(SOCKET clientSock, bool* ptTerm) 
{ 
    terminate = ptTerm; 
    //client = std::thread(&StreamServerClient::DoNothing, this);  //Same thing as the declaration 
} 

StreamServerClient::StreamServerClient() 
{ 
    *terminate = false; 
    //client = std::thread(&StreamServerClient::DoNothing, this);  //Same thing as the declaration 
} 

void StreamServerClient::DoNothing() 
{ 
} 

StreamServerClient::~StreamServerClient() 
{ 
} 

void StreamServer::Listen() 
{ 
    {...} 
    do { 
     clients.push_back(StreamServerClient::StreamServerClient(accept(listenSock, NULL, NULL), &terminate)); 
     std::cout << "accepted a client!" << std::endl; 
    } while (!terminate); 
} 

StreamServer::StreamServer() 
{ 
    terminate = false; 
    Listener = std::thread(&StreamServer::Listen, this); 
    Listener.detach(); 
} 

StreamServer::~StreamServer() 
{ 
} 
+1

'std :: thread's不能被複制。又名,複製構造函數被「刪除」。 – 2013-12-21 21:09:56

+0

@remyabel但是爲什麼我能夠爲StreamServer做到這一點呢?我在這裏錯過了什麼? – Mismatch

+0

@remyabel廢話,我想我只是注意到會發生什麼......如果我註釋掉'clients.push_back(...)',它也會消失。我應該使用'std :: thread *'來代替嗎? – Mismatch

回答

9

類型std::thread的對象不能被複制。你是最好的關閉只是初始化成員初始化列表中的對象:

class StreamServerClient 
{ 
public: 
    bool* terminate; 
    std::thread client; 
    void DoNothing(); 
    StreamServerClient(SOCKET clientSock, bool* ptTerm); 
    StreamServerClient(StreamServerClient&& other); 
    ~StreamServerClient(); 
}; 

StreamServerClient::StreamServerClient(SOCKET clientSock, bool* ptTerm) 
    : terminate(ptTerm) 
    , client(std::thread(&StreamServerClient::DoNothing, this)) { 
} 
StreamServerClient::StreamServerClient(StreamServerClient&& other) 
    : terminate(other.terminate) 
    , client(std::move(other.client)) { 
} 

我忽略,則默認構造函數(請注意,你的版本不工作,因爲它試圖將值賦給訪問一個未初始化的結果指針),而是增加了一個移動構造函數:推回std::vector<...>當此構造函數將提供一些東西,看起來像一個臨時的(在使用被稱爲即一些東西,無論是臨時或者使其看起來像一個,例如, std::move())。

+0

我真搞不清楚什麼成員初始化列表有什麼關係。這與在構造函數中進行初始化有何不同,在這種情況下呢? –

+0

@Andrey:初始化列表初始化。賦值賦值。不同的方法。 – MSalters

+1

@Andrey:你也可以初始化身體中的東西,但這將等於第一個默認構造對象,然後[移動]分配給它。沒有必要這樣做。無可否認,當我第一次閱讀這個問題時,我也錯過了'push_back()'。 –

6

一個std::thread對象是不可拷貝。當此行被稱爲:

clients.push_back(StreamServerClient::StreamServerClient(accept(listenSock, NULL, NULL), &terminate)); 

創建需要StreamServerClient對象添加到clients載體,但要做到這一點的唯一方法是通過複製它,因爲你的StreamServer對象沒有定義的移動構造函數。生成StreamServerClient的默認拷貝構造函數,並且C++ 11中默認的拷貝構造函數的作用是調用所有數據成員的拷貝構造函數。

在這種情況下,它調用std::thread數據成員的拷貝構造函數,該數據成員被刪除。

原因std::thread s不能被複制的是一個std::thread對象對應於一個執行線程。你應該重構你的代碼,IMO。您可以將StreamServerClient的移動構造函數一起入侵,但我認爲有更清晰的解決方案,例如,用指向std::thread的指針替換std::thread,並用完全單獨的調用初始化線程。

編輯:一般而言,我認爲在對象的構造器中分支新線程是不明智的,因爲它太過於微妙的操作。 (它可能會失敗,那麼你必須處理異常等)。雖然C++純粹主義者可能會不同意我的看法。

編輯:有愚蠢的術語。

+0

「一招拷貝構造函數」笏 – Griwes

+0

@Griwes感謝,是的,這是一個愚蠢的錯誤 –

相關問題