passing a reference to virtual class implementation as thread argument

1k views Asked by At

Once again I need your help making std::thread work with templated objects. This time my issue is in one of the arguments.

I try passing a reference to a (valid) instantiation of a virtual class as one of the arguments of my thread, and it just doesn't work. Note that passing a pointer instead of a reference solves everything. But still, why can't I give a reference (which I prefer, for many reasons)

Small code reproducing my error :

#include <cstdio>
#include <thread>
#include <vector>

template<typename T>
class functor { public: virtual T operator()(T) const = 0; };

template<typename T>
class square : public functor<T>
{
    public:
        T operator()(T f) const { return f*f; }
};

template<typename T>
void thread(const functor<T>& func, size_t imin, size_t imax) // line1
{
    for(size_t i=imin; i<imax; ++i)
    {
        T arg = T(i);
        std::cout << arg << "=>" << (func)(arg)) << std::endl; // line2
    }
}

template<typename T>
void threadlauncher(const functor<T>& func, size_t imin, size_t imax, size_t nbthread)
{
    size_t window = (imax-imin)/nbthread + ((imax-imin)%nbthread?1:0);
    std::vector<std::thread> threads;
    for (size_t idthread=0; idthread<nbthread; ++idthread)
    {
        size_t tmin = std::min(window*(idthread+0), imax);
        size_t tmax = std::min(window*(idthread+1), imax);
        threads.push_back(
            std::thread(&thread<T>, func, tmin, tmax) // line3
        );
    }
    for (std::thread& thread : threads)
        thread.join();
}
int main()
{
    square<float> func;
    threadlauncher<float>(func, 0, 10, 3);
    return 0;
}

The compiler (gcc 4.9.2) tells me that my object is invalid because operator() is virtual in threadlauncher

Note that changing code to pass thread's argument using pointers solves this

void thread(const functor<T>* func, size_t imin, size_t imax) // line1
std::cout << arg << "=>" << (*func)(arg)) << std::endl; // line2
std::thread(&thread<T>, &func, tmin, tmax) // line3

How can I make him understand that my reference is valid ?

Edit

I get an long/unreadeble error message from the compiler. I guess the important part is

src/functorthreads.cc:50:38:   required from here
/usr/include/c++/4.9.2/functional:1713:9: erreur: invalid abstract parameter type ‘functor<float>’
         __type;
         ^
src/functorthreads.cc:6:7: note:   because the following virtual functions are pure within ‘functor<float>’:
 class functor
       ^
src/functorthreads.cc:9:13: note:   T functor<T>::operator()(T) const [with T = float]
   virtual T operator()(T) const = 0;
1

There are 1 answers

1
Jay Miller On BEST ANSWER

std::thread takes copies of it's arguments. It doesn't matter that the argument to the function is a reference....the thread constructor will still copy the arguments since they are being passed to another thread. That's why pointers work, since they are being copied.

If you know that your object will remain in scope throughout the lifetime of the thread, you can use std::ref to wrap your argument:

std::thread(&thread<T>, std::ref(func), tmin, tmax)