Error creating std::thread on Mac OS X with clang: "attempt to use a deleted function"

Violet Giraffe picture Violet Giraffe · Aug 19, 2013 · Viewed 13.8k times · Source

Consider my test code:

#include <thread>

class Foo {
public:
    void threadFunc() {}
    void startThread() {
        _th = std::thread(&Foo::threadFunc, *this);
    }
private:
    std::thread _th;
};

int main(int argc, char *argv[])
{    
    Foo f;
    f.startThread();
    return 0;
}

This is an error it produces:

../untitled/main.cpp:13:14: warning: unused parameter 'argc' [-Wunused-parameter]
int main(int argc, char *argv[])
             ^
../untitled/main.cpp:13:26: warning: unused parameter 'argv' [-Wunused-parameter]
int main(int argc, char *argv[])
                         ^
In file included from ../untitled/main.cpp:1:
In file included from /usr/bin/../lib/c++/v1/thread:90:
In file included from /usr/bin/../lib/c++/v1/__functional_base:15:
/usr/bin/../lib/c++/v1/type_traits:1372:12: error: call to implicitly-deleted copy constructor of 'typename decay<Foo &>::type' (aka 'Foo')
    return _VSTD::forward<_Tp>(__t);
           ^~~~~~~~~~~~~~~~~~~~~~~~
/usr/bin/../lib/c++/v1/__config:273:15: note: expanded from macro '_VSTD'
#define _VSTD std::_LIBCPP_NAMESPACE
              ^
/usr/bin/../lib/c++/v1/thread:351:33: note: in instantiation of function template specialization 'std::__1::__decay_copy<Foo &>' requested here
                                __decay_copy(_VSTD::forward<_Args>(__args))...));
                                ^
../untitled/main.cpp:7:15: note: in instantiation of function template specialization 'std::__1::thread::thread<void (Foo::*)(), Foo &, void>' requested here
        _th = std::thread(&Foo::threadFunc, *this);
              ^
../untitled/main.cpp:10:17: note: copy constructor of 'Foo' is implicitly deleted because field '_th' has an inaccessible copy constructor
    std::thread _th;
                ^

And if I create a thread like this: _th = std::thread(&Foo::threadFunc, std::ref(*this));

I get:

../untitled/main.cpp:13:14: warning: unused parameter 'argc' [-Wunused-parameter]
int main(int argc, char *argv[])
             ^
../untitled/main.cpp:13:26: warning: unused parameter 'argv' [-Wunused-parameter]
int main(int argc, char *argv[])
                         ^
In file included from ../untitled/main.cpp:1:
/usr/bin/../lib/c++/v1/thread:330:5: error: attempt to use a deleted function
    __invoke(_VSTD::move(_VSTD::get<0>(__t)), _VSTD::move(_VSTD::get<_Indices>(__t))...);
    ^
/usr/bin/../lib/c++/v1/thread:340:5: note: in instantiation of function template specialization 'std::__1::__threaad_execute<void (Foo::*)(), std::__1::reference_wrapper<Foo> , 1>' requested here
    __threaad_execute(*__p, _Index());
    ^
/usr/bin/../lib/c++/v1/thread:352:41: note: in instantiation of function template specialization 'std::__1::__thread_proxy<std::__1::tuple<void (Foo::*)(), std::__1::reference_wrapper<Foo> > >' requested here
    int __ec = pthread_create(&__t_, 0, &__thread_proxy<_Gp>, __p.get());
                                        ^
../untitled/main.cpp:7:15: note: in instantiation of function template specialization 'std::__1::thread::thread<void (Foo::*)(), std::__1::reference_wrapper<Foo> , void>' requested here
        _th = std::thread(&Foo::threadFunc, std::ref(*this));
              ^
/usr/bin/../lib/c++/v1/type_traits:833:5: note: function has been explicitly marked deleted here
    ~__nat() = delete;
    ^

What am I doing wrong? I don't have such problem on Windows with VS2012. I also didn't have this problem with default stdlib implementation on Mac, but now I have to use libc++.

My compiler flags: -std=c++11 -mmacosx-version-min=10.7 -stdlib=libc++

Answer

Jonathan Wakely picture Jonathan Wakely · Aug 19, 2013
    _th = std::thread(&Foo::threadFunc, *this);

This tries to make a copy of *this to store in the new thread object, but your type is not copyable because its member _th is not copyable.

You probably want to store a pointer to the object, not a copy of the object:

    _th = std::thread(&Foo::threadFunc, this);

N.B. your program will terminate because you do not join the thread. In your type's destructor you should do something like:

~Foo() { if (_th.joinable()) _th.join(); }