ErniBrown
ErniBrown

Reputation: 1372

Vector of elements containing std::threads

I've got a class Tester containing an std:thread object, and an std::vector of Tester. I understand that I can't copy threads, so the push_back is out of the question, but why emplace_back is not working? Where is the copy in my code?

#include <iostream>
#include <thread>
#include <vector>
#include <functional>
#include <unistd.h>

class Tester
{
public:
    Tester(std::function<void(void)> func) : 
        th(func)
    {
    }

    ~Tester()
    {
        th.join()
    }

private:
    std::thread th;
};

std::vector<Tester> testers;

void InnerHelloWorld()
{
    std::cout << "Hello from the inner word!\n";
}

int main() {
    std::cout << "Hello World!\n";

    for(size_t i = 0 ; i < 4 ; i++)
    {
        testers.emplace_back(InnerHelloWorld);
    }

    sleep(1);

    return 0;
}

Upvotes: 8

Views: 1157

Answers (2)

user7860670
user7860670

Reputation: 37488

You need to define move constructor for your class so it becomes MoveInsertable and will satisfy requirements of emplace method:

Tester(Tester && other) : 
    th(::std::move(other.th))
{
}

Another problem that will arise once you fix lack of move constructor is an attempt to join thread that is not nessesery joinable since actual thread could have been moved into another object. So you need to add a corresponding check:

~Tester()
{
   if(th.joinable())
   {
       th.join();
   }
}

Upvotes: 3

Mike Vine
Mike Vine

Reputation: 9837

Theres a couple of minor issues in your code

You missed the trailing semi-colon off of:

th.join()

But importantly, you need to give your class a move constructor - the default one is fine:

Tester(Tester&&) = default;

This is needed as when vectors resize themselves they need to move or copy their elements. A move constructor will generally be created for you but in your case having a custom destructor supresses it. See here.

This will let your code compile, but then it'll throw an exception at runtime. This is because you sometimes destruct from moved-from Testers which will call join on a moved from thread. Fortunately this is an easy fix:

~Tester()
 {
   if(th.joinable())
       th.join();
 }

Full working code:

#include <iostream>
#include <thread>
#include <vector>
#include <functional>

#include <unistd.h>

class Tester
{
  public:
  Tester(std::function<void(void)> func) : 
    th(func)
  {
  }

  ~Tester()
  {
    if(th.joinable())
        th.join();
  }

  Tester(Tester&&) = default;

  private:
  std::thread th;
};

std::vector<Tester> testers;

void InnerHelloWorld()
{
  std::cout << "Hello from the inner word!\n";
}

int main() {
  std::cout << "Hello World!\n";

  for(size_t i = 0 ; i < 4 ; i++)
  {
    testers.emplace_back(InnerHelloWorld);
  }

  sleep(1);

  return 0;
}

Upvotes: 16

Related Questions