2013-12-21 9 views
7

У меня возникла проблема с созданием статической библиотеки VC++, которая использует стандарт C++ 11 потоки.Ошибка C2280: 'std :: thread :: thread (const std :: thread &)': попытка ссылки на удаленную функцию

В настоящее время у меня есть два класса, и я могу объявить, а потом определить поток просто отлично в своем стартовом классе (который объявлен последним). На этом этапе код представляет собой только прослушиватель сокетов, который затем создает объект другого класса для обработки каждого принятого клиента. Эти дочерние объекты должны создавать потоки, которые мне нужны для параллельного сбора данных, кодирования и передачи.

Проблема: если я объявляю зЬй :: нить на моем другом классе, даже если точно, как я сделал на моем начальном классе, независимо от того, что я не получаю эту ошибку на сборке 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' не может быть скопирован. Aka, конструктор копирования «удален». –

+0

@remyabel Но тогда почему я могу сделать это просто отлично для StreamServer? Что мне здесь не хватает? – Mismatch

+0

@remyabel Crap, думаю, я только что заметил, что происходит ... Он также исчезает, если я прокомментирую '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)) { 
} 

I конструктор пропущены по умолчанию (обратите внимание, что ваша версия не работает, потому что он пытается присвоить значение результата разыменования неинициализированного указатель) и вместо этого добавил конструктор перемещения: при нажатии на std::vector<...> этот конструктор будет вызываться при предоставлении чего-то, что выглядит как временное (то есть то, что либо равно, либо временное, либо оно выглядит как одно, например, используя std::move()).

+0

Я действительно смущен тем, что список инициализаторов членов имеет что-то. Как это отличается от выполнения инициализации в конструкторе, в этом случае? –

+0

@Andrey: инициализатор инициализирует списки инициализации. Назначения назначаются. Различные методы. – MSalters

+1

@Andrey: вы также можете инициализировать вещи в теле, но это будет означать, что сначала по умолчанию будет создан объект, а затем [move], назначая ему. Нет необходимости делать это. С удовольствием, я также пропустил '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 соответствует потоку выполнения. Вы должны реорганизовать свой код, ИМО. Вы могли бы взломать конструктор перемещения для StreamServerClient, но я думаю, что есть более чистые решения, например, заменяя std::thread указателем на std::thread и инициализируя поток с полностью раздельным вызовом.

Редактировать: В общем, я бы сказал, что неразумно разветвлять новый поток в конструкторе объекта, потому что это слишком тонкая операция. (Это может потерпеть неудачу, тогда вам придется иметь дело с исключениями и т. Д.) Хотя, вероятно, пуристы C++ будут не согласны со мной.

Редактировать: Имел глупую терминологию.

+0

«конструктор копирования перемещения» wat – Griwes

+0

@ Griwes спасибо, да, это глупая ошибка –

Смежные вопросы