简体   繁体   中英

How to vector::emplace_back a class that has a shared_mutex?

How can I emplace_back a class that has a shared_mutex?

It looks like that a shared_mutex makes a class no longer MoveConstructible/CopyConstructible.

Compiling my code gives me result type must be constructible from value type of input range . And no matching function for call to construct_at(class_with_lock*&, class_with_lock) .

Minimal example:

//compile me with g++ -std=c++2a lock.cpp -o lock
//tested under linux with gcc 11.1
#include <vector>
#include <shared_mutex>

class class_with_lock {
    public:
    class_with_lock(){}
    
    void do_lock(void) {
        std::shared_lock lock(my_lock);
    }
    
    private:
    mutable std::shared_mutex my_lock;
};
    
class my_vector_class {
    public:
    my_vector_class() {
        my_vector.emplace_back(class_with_lock{});
    }
    private:
    std::vector<class_with_lock> my_vector;
};

int main(void) {
    my_vector_class my_class;
    return 0;
}

std::shared_mutex is not copyable , however std::vector s require copyable/movable objects.

You cannot use a vector with a std::shared_mutex or objects that have one, unless you have a user-defined copy/move constructor that do whatever it means for those objects to be copied/moved, but without the corresponding std::shared_mutex .

You can also switch to a different container that can support non-copyable/movable objects, like std::list .

Mutexes are not safe to copy/move in general; it simply doesn't compile, and the action itself doesn't make sense.

If you have a type with a mutex, and you are copy/moving it, you are almost certainly doing something wrong.

A vector of a class with a lock is bad smell, don't do it.

The semantics start acting really, really strange.

If an object has a mutex, that mutex has an identity more so than it has a value. You don't have the value of that mutex locked, you have the identity of that mutex locked. Identities cannot be copied, so classes with mutexes in them either cannot be copied, or do mix-semantics copy/move operations where part of their state is copied/moved, and the rest isn't.

Mixed semantics types are bonkers, and are ridiculously hard to reason about. This is the same reason why one struct shouldn't contain both a reference and a value, but much much worse.

std::vector is designed for regular or semi-regular value types. When you emplace, it may allocate a new buffer and move the elements over to it.

Putting a type with a mutex in it means that regular or semi-regular semantics are incoherent on them; it cannot apply to its entire state.

It is possible to make it work, but it isn't a good plan. What you'd do is write your incoherent copy/move ctors and assignment operations that don't duplicate/move the mutex state, and do something to the rest of the state. There could possibly be some locking involved there, but even that gets nasty and tricky.

(Mutex based threading doesn't compose; now you have incoherent values guarded by multiple locks being copied around. It will end badly.)

(Incoherent here refers to the mixed semantics; part of the object (the mutex) isn't copied/moved, the value meanwhile is. Coherent semantics means "the class all follows the same semantics", incoherent means it doesn't have coherent semantics.)

The least insane option involves using std::lock to lock the mutexes of the source/destination object before you do the assignment, and on construction don't bother locking the destination (just the source) because no other thread should have access to the object while it is being constructed.

I mean, I've done that.

It isn't a good plan.


A slightly less bad plan is to have a vector of unique pointers to your class. Here the identity of the objects isn't disposable; the vector holds unique_ptr s (which are semi-regular, hence can sensibly be moved), which in turn point to objects with a stable identity.

A mutex in those is somewhat reasonable. Having a dynamic vector of such mutexes is often a bad sign (bad code smell), but it isn't complete insanity.

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