передача ссылки на реализацию виртуального класса в качестве аргумента потока

0

Еще раз мне нужна ваша помощь, помогая std::thread работать с шаблонами. На этот раз моя проблема находится в одном из аргументов.

Я пытаюсь передать ссылку на (действительное) создание виртуального класса как один из аргументов моего потока, и он просто не работает. Обратите внимание, что передача указателя вместо справки решает все. Но все же, почему я не могу дать ссылку (которую я предпочитаю по многим причинам)

Небольшой код, воспроизводящий мою ошибку:

#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;
}

Компилятор (gcc 4.9.2) сообщает мне, что мой объект недействителен, потому что operator() является виртуальным в threadlauncher

Обратите внимание, что изменение кода для передачи аргумента потока с помощью указателей решает эту проблему

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

Как я могу заставить его понять, что моя ссылка действительна?

редактировать

Я получаю сообщение об ошибке long/unreadeble от компилятора. Я думаю, что важная часть

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;
  • 0
    Какую именно ошибку выдает компилятор? Скорее всего, вы пытаетесь создать экземпляр functor<T> при создании потока.
  • 0
    Я редактирую свой пост, полагая, что это важная часть (очень длинной) ошибки компилятора.
Показать ещё 1 комментарий
Теги:
c++11
reference
stdthread
virtual-inheritance

1 ответ

1
Лучший ответ

std::thread принимает копии своих аргументов. Не имеет значения, что аргумент функции является ссылкой... конструктор thread прежнему будет копировать аргументы, поскольку они передаются в другой поток. Вот почему работают указатели, поскольку они копируются.

Если вы знаете, что ваш объект останется в области действия на протяжении всего жизненного цикла потока, вы можете использовать std::ref чтобы обернуть свой аргумент:

std::thread(&thread<T>, std::ref(func), tmin, tmax)
  • 0
    Спасибо. Кроме этого, поток моего реального приложения имеет векторы в своем аргументе. Упаковка всего в std::cref решила проблему с улучшенной производительностью (не требуется копирование). Мне интересно, почему std::thread делает копию? Это чтобы избежать гонок данных?

Ещё вопросы

Сообщество Overcoder
Наверх
Меню