I'm having a problem trying to create a VC++ Static Library that uses C++11 standard threads.
I currently have two classes, and I am able to declare and later define a thread just fine on my starting class (which is declared last). At this stage, the code is just a socket listener which then creates an object of another class to handle each client accepted. Those child objects are supposed to create the threads I need for parallel data capture, encoding and transmission.
The problem is: If I declare a std::thread on my other class, even if exactly like I did on my start class, no matter what, I'm getting this error on build error C2280: 'std::thread::thread(const std::thread &)' : attempting to reference a deleted function [...]\vc\include\functional 1124 1
The only way I was able to workaround this error is to simply not declare a std::thread
object in the latter class, which isn't possible, according to what I want it to do...
I'm using VS2013, and my sources are:
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()
{
}
Objects of type std::thread
can't be copied. You are best off to just initialize the objects in the member initializer list:
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 ommitted the default constructor (note that your version doesn't work because it tries to assign a value to the result of dereferencing an uninitialized pointer) and instead added a move constructor: when pushing back to the std::vector<...>
this constructor will be called when providing something which looks like a temporary (i.e., something which either is a temporary or is made to look like one, e.g., using std::move()
).
An std::thread
object is not copyable. When this line is called:
clients.push_back(StreamServerClient::StreamServerClient(accept(listenSock, NULL, NULL), &terminate));
The StreamServerClient
object you create needs to be added to the clients
vector, but the only way to do that is by copying it because your StreamServer
object does not have a move constructor defined. The default copy constructor for StreamServerClient
is generated, and what the default copy constructor in C++11 does is, it calls the copy constructors of all of the data members.
In this case it is calling the copy constructor of the std::thread
data member, which is deleted.
The reason std::thread
s can't be copied is that a std::thread
object corresponds to a thread of execution. You should refactor your code, IMO. You could hack together a move constructor for StreamServerClient
, but I think there are cleaner solutions, for example, replacing the std::thread
with a pointer to std::thread
and initializing the thread with a completely separate call.
Edit: In general I would say it is unwise to branch a new thread in an object's contructor, because it is too delicate an operation. (It can fail, then you have to deal with exceptions, etc.) Although probably C++ purists will disagree with me.
Edit: Had stupid terminology.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With