Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Error C2280: 'std::thread::thread(const std::thread &)' : attempting to reference a deleted function

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()
{
}
like image 945
Mismatch Avatar asked Dec 21 '13 21:12

Mismatch


2 Answers

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()).

like image 184
Dietmar Kühl Avatar answered Oct 19 '22 17:10

Dietmar Kühl


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::threads 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.

like image 37
Andrey Mishchenko Avatar answered Oct 19 '22 17:10

Andrey Mishchenko