简体   繁体   中英

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

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

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();
   }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM