1 #ifndef LOCK_GUARDED_CONTAINER_HPP_
2 #define LOCK_GUARDED_CONTAINER_HPP_
3 
4 #include <mutex>
5 
6 /* This is a bundle of a container (well, in fact, of anything) plus a
7  * lock. The copy/move work just the same as they do (or don't) in the
8  * original container, while a lock is created afresh for each new
9  * object. Moves don't move the mutexes.
10  */
11 
12 template<typename T> struct lock_guarded_container : public T {
13     private:
14     mutable std::mutex mm;
15     public:
mutexlock_guarded_container16     std::mutex & mutex() const { return mm; }
17     /* forward the constructors of the embedded container. No lock needed
18      * here. */
lock_guarded_containerlock_guarded_container19     template<typename... Args> lock_guarded_container(Args&& ...args) :
20         T(std::forward<Args>(args)...) {}
21     /* add a few of our own to circumvent the lack of copy/move for the
22      * mutex.
23      * We considered having a dedicated (private) ctor taking a transient
24      * lock_guard object, so that we can avoid the cost of
25      * constructing+assigning, and construct the T base simply in the
26      * initializer list by delegating to this private ctor. Alas, this is
27      * incompatible with our perfect forwarding of the constructors of T.
28      * I don't know if a workaround is possible.
29      */
lock_guarded_containerlock_guarded_container30     lock_guarded_container(lock_guarded_container<T> const & o)
31     {
32         std::lock_guard<std::mutex> foo(o.mutex());
33         (T&)*this = (T const&) o;
34     }
lock_guarded_containerlock_guarded_container35     lock_guarded_container(lock_guarded_container<T> && o)
36     {
37         std::lock_guard<std::mutex> foo(o.mutex());
38         std::lock_guard<std::mutex> bar(mutex());
39         std::swap((T&)*this, (T&) o);
40     }
operator =lock_guarded_container41     lock_guarded_container& operator=(lock_guarded_container<T> const & o) {
42         std::lock_guard<std::mutex> foo(o.mutex());
43         std::lock_guard<std::mutex> bar(mutex());
44         (T&)*this = (T const&) o;
45         return *this;
46     }
operator =lock_guarded_container47     lock_guarded_container& operator=(lock_guarded_container<T> && o) {
48         std::lock_guard<std::mutex> foo(o.mutex());
49         std::lock_guard<std::mutex> bar(mutex());
50         std::swap((T&)*this, (T&) o);
51         return *this;
52     }
53 };
54 
55 #endif	/* LOCK_GUARDED_CONTAINER_HPP_ */
56