Mutex Protected Object (scoped object wrapper) This is a class that holds mutex and associated object. On checkout/access the mutex is locked while the stack object lives and a reference to object is obtained. Any suggestions or improvements is welcomed.

#include &lt;mutex&gt;

template&lt;class T&gt;
class MutexProtectedObject {
  //this relies on benign use and it is just a helper rather than a foolproof solution - ie. anyone may still save a pointer to obj etc. and access it later
public:
  class Access {
  public:
    Access(std::mutex&amp; m, T&amp; obj) : sl_(m), obj_(obj) {
    }
    T&amp; obj_;
  private:
    std::scoped_lock&lt;std::mutex&gt; sl_;//mutex is locked here (by RAII)
  };

  Access access() {
    return Access(mutex, obj);
  }

  MutexProtectedObject(const MutexProtectedObject&amp;) = delete;
  MutexProtectedObject&amp; opreator=(const MutexProtectedObject&amp;) = delete;

private:
  std::mutex mutex;
  T obj;
};
Access

I don't like the fact that Access gives you a reference to the object directly. This leads to issues with somebody accidentally keeping a reference to the object after the Accesses object is destroyed or accidentally making a copy of the object.

T&amp;  myRef = wrapped.access().obj_;   // Now I have a reference to the object
                                     // But the Accesses object is gone.

myRef.doStuffWithNoLock();


// or

T   myCopy = wrapped.access().obj_;  // I made a copy of the object.


How about Access delegating all accesses via operator -&gt;? That way you don't leak the object to external code.

class Access
{
    public:
        T* operator-&gt;() {return &amp;obj_;}
    private:
        T&amp;  obj_;
};


Now you can use Access like it was a T*:

auto foo = wrapper.access();
foo-&gt;fun1(args);
foo-&gt;fun2(args);


Initializer list

The order of initialization of members is the order of declaration. If you define the order deferently in the initializer list this can be confusing (most compilers will warn you about it).

class Access {
    public:
    Access(std::mutex&amp; m, T&amp; obj)
        : sl_(m)             // This is not the order they are
        , obj_(obj)          // initialized in. The obj_ will be done first
    {}

    T&amp; obj_;

    private:
    std::scoped_lock&lt;std::mutex&gt; sl_;//mutex is locked here (by RAII)
};


Best practice is to keep the initializer list in the same order as the declaration order in the class.