Jane Doe
Jane Doe

Reputation: 560

emplace_back an object containing a mutex

I'm trying to create a vector of threads that perform a search. This is the important stuff from my SearchThread class.

class SearchThread {

        explicit SearchThread(int t_id) {
            id = t_id;
            run = true;

            thread = std::jthread([&]{
                while(run){
                    {
                        std::unique_lock lock(mtx);
                        cnd_var.wait(lock, [&] { return !run; });
                        if(!run) { return; }
                    }
                    Search();
                }
            });
        }
        
       void Search();

        int id;
        bool run;
        std::jthread thread;
        std::condition_variable cnd_var;
        std::mutex mtx;
}

And i'm attempting to construct them like this.

        std::vector<SearchThread> search_threads;
        for (int t_id = 0; t_id < num_threads; t_id++) {
            search_threads.emplace_back(t_id);
        }

The error i'm getting is no matching function for call to 'construct_at'. The issue i believe is with std::mutex and std::conditional_variable. I can have the mutex and conditional variable declared as pointers and then construct them on the heap in the class constructor, however that seems very ugly to me.

I guess my question is, why am i not allowed to do it like this, and is there a way around it?

Upvotes: 3

Views: 968

Answers (1)

Sam Varshavchik
Sam Varshavchik

Reputation: 118445

std::mutex is not copyable. Its copy constructor is deleted. "Copying a mutex" makes no logical sense. If the mutex is locked, what does that mean? Is the copy-constructed mutex is also locked? If so, who locked it? Who gets to unlock it?

This makes the SearchThread class also uncopyable, and have a deleted copy constructor. Since one of its members is an uncopyable std::mutex, that pretty much puts a kibosh on copy-ability of a SearchThread, too.

std::vector requires its contents to be copyable. One of std::vector's proud achievements is that it will automatically copy the values in the vector, as needed, when it grows. This requires its contents to be copyable. SearchThread is not copyable. You cannot put it into a vector. It doesn't matter how you try to put it, emplace_back, or some other way. reserve() won't help you. A std::vector must contain a copyable class, there is no workaround for that.

Your options are:

  1. Provide a user-defined copy constructor for your SearchThread, that implements whatever it means for a SearchThread to be copy-constructed from another instance of SearchThread. Perhaps its sufficient to copy all of its other members, and just have the copy-constructed SearchThread default-construct its mutex. You also have to provide a user-defined assignment operator as well. Or implement user-defined move constructor and assignment operator. The bottom line is: somehow make your SearchThread copyable/movable/assignable.

  2. Use some other container that does not require a copyable object, like std::list perhaps.

Upvotes: 3

Related Questions