1
votes

Need to have this Functor live as long as my thread does, so I've created a shared_ptr to it and trying to pass it to std::thread. I've copied the code and list of errors here.

struct Functor
{
    std::string greeting;
    explicit Functor(std::string _greeting="Hello!"): greeting { _greeting }     {}
    void operator()()
    {
        std::cout << greeting << "\n";
    }
};

auto main() ->int 
{
    std::shared_ptr<Functor> fp = std::make_shared<Functor> ();
    std::thread t(&fp);
    t.join();
    return 0;
}

List of errors:

Error   C2893   Failed to specialize function template 'unknown-type std::invoke(_Callable &&,_Types &&...)'    std_threads C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\include\thr\xthread  240 
Error   C2672   'std::invoke': no matching overloaded function found    std_threads C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\include\thr\xthread  240 

I'm new to c++11 and concurrency. Please help me understand the following

1>does a std::thread always invoke the operator() inside an object when passed by value ? If so, why it has been defined so.

2>how to ensure that a resource given to a thread stays around as long as the thread does?

3>is the Functor written here, a function object ?

4>What have I done here in this code ?!

3
shouldn't it be std::thread t(*fp) instead? - kmdreko

3 Answers

1
votes

1>does a std::thread always invoke the operator() inside an object when passed by value ? If so, why it has been defined so.

std::thread invokes std::invoke. From cppreference, if the first argument is neither a pointer to member function nor a pointer to data member; it is treated as a function object. So, fp() will be called.

INVOKE(f, t1, t2, ..., tN) is equivalent to f(t1, t2, ..., tN) (that is, f is a FunctionObject)

So you can basically do std::thread t{*fp}

2>how to ensure that a resource given to a thread stays around as long as the thread does?

You can have shared_ptr to provide ownership of a shared object. Or you can just manually do it by ensuring the resource passed is in scope. The mileage varies.

3>is the Functor written here, a function object ?

Yes. A FunctionObject type is the type of an object that can be used on the left of the function call operator. However fp is not. But *fp is.

4>What have I done here in this code ?!

You can make it work by explicitly passing Functor::operator() with argument fp.get(). Ofcourse a simple way is to just pass *fp

Demo

1
votes

std::shared_ptr<Functor> is not callable - it doesn't implement operator(), even while Functor does.

What's the purpose of shared_ptr here? Why not simply

int main() {
    Functor f;
    std::thread t(std::ref(f));
    t.join();
    return 0;
}

If for some reason you insist on having Functor instance managed by a shared_ptr, here's one way:

int main() {
    std::shared_ptr<Functor> fp = std::make_shared<Functor> ();
    std::thread t([fp]() { (*fp)(); });
    t.join();
    return 0;
}
0
votes

You can still make std::thread take ownership of your smart pointer with this syntax:

std::shared_ptr<Functor> f = std::make_shared<Functor>();
std::thread thread (&Functor::operator(), f);
thread.detach();

If the first argument is a member function pointer, then the second argument is expected to be a reference or pointer to an instance of the class and std::shared_ptr<Functor> is accepted. When the thread finishes, the smart pointer will be deleted.

Downside: removes the benefit of having a functor because you have to specify the member function.