Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>I prefer to use a non-intrusive wrapper class instead of polluting the original object with a mutex and locking it on each method call. This wrapper class (which I named <code>Protected&lt;T&gt;</code>) contains the user object as a private variable. <code>Protected&lt;T&gt;</code> grants friendship to another class called <code>Locker&lt;T&gt;</code>. The locker takes the wrapper as its constructor argument and provides public accessor methods to the user object. The locker also keeps the wrapper's mutex locked during its lifetime. So the locker's lifetime defines a scope where the original object can be accessed in a safe way.</p> <p>The <code>Protected&lt;T&gt;</code> can implement <code>operator-&gt;</code> to enable quickly calling a single method.</p> <p>Working example:</p> <pre><code>#include &lt;iostream&gt; #include &lt;mutex&gt; template&lt;typename&gt; struct Locker; template&lt;typename T&gt; struct Protected { template&lt;typename ...Args&gt; Protected(Args &amp;&amp; ...args) : obj_(std::forward&lt;Args&gt;(args)...) { } Locker&lt;const T&gt; operator-&gt;() const; Locker&lt;T&gt; operator-&gt;(); private: friend class Locker&lt;T&gt;; friend class Locker&lt;const T&gt;; mutable std::mutex mtx_; T obj_; }; template&lt;typename T&gt; struct Locker { Locker(Protected&lt;T&gt; &amp; p) : lock_(p.mtx_), obj_(p.obj_) { std::cout &lt;&lt; "LOCK" &lt;&lt; std::endl; } Locker(Locker&lt;T&gt; &amp;&amp; rhs) = default; ~Locker() { std::cout &lt;&lt; "UNLOCK\n" &lt;&lt; std::endl; } const T&amp; get() const { return obj_; } T&amp; get() { return obj_; } const T* operator-&gt;() const { return &amp;get(); } T* operator-&gt;() { return &amp;get(); } private: std::unique_lock&lt;std::mutex&gt; lock_; T &amp; obj_; }; template&lt;typename T&gt; struct Locker&lt;const T&gt; { Locker(const Protected&lt;T&gt; &amp; p) : lock_(p.mtx_), obj_(p.obj_) { std::cout &lt;&lt; "LOCK (const)" &lt;&lt; std::endl; } Locker(Locker&lt;const T&gt; &amp;&amp; rhs) = default; ~Locker() { std::cout &lt;&lt; "UNLOCK (const)\n" &lt;&lt; std::endl; } const T&amp; get() const { return obj_; } const T* operator-&gt;() const { return &amp;get(); } private: std::unique_lock&lt;std::mutex&gt; lock_; const T &amp; obj_; }; template&lt;typename T&gt; Locker&lt;T&gt; Protected&lt;T&gt;::operator-&gt;() { return Locker&lt;T&gt;(const_cast&lt;Protected&lt;T&gt;&amp;&gt;(*this)); } template&lt;typename T&gt; Locker&lt;const T&gt; Protected&lt;T&gt;::operator-&gt;() const { return Locker&lt;T&gt;(const_cast&lt;Protected&lt;T&gt;&amp;&gt;(*this)); } struct Foo { void bar() { std::cout &lt;&lt; "Foo::bar()" &lt;&lt; std::endl; } void car() const { std::cout &lt;&lt; "Foo::car() const" &lt;&lt; std::endl; } }; int main() { Protected&lt;Foo&gt; foo; // Using Locker&lt;T&gt; for rw access { Locker&lt;Foo&gt; locker(foo); Foo &amp; foo = locker.get(); foo.bar(); foo.car(); } // Using Locker&lt;const T&gt; for const access { Locker&lt;const Foo&gt; locker(foo); const Foo &amp; foo = locker.get(); foo.car(); } // Single actions can be performed quickly with operator-&gt; foo-&gt;bar(); foo-&gt;car(); } </code></pre> <p>Which generates this output:</p> <pre><code>LOCK Foo::bar() Foo::car() const UNLOCK LOCK (const) Foo::car() const UNLOCK (const) LOCK Foo::bar() UNLOCK LOCK Foo::car() const UNLOCK </code></pre> <p><a href="http://coliru.stacked-crooked.com/view?id=c3c08cda10533b8a6e52963083262350-50d9cfc8a1d350e7409e81e87c2653ba" rel="nofollow">Test with online compiler.</a></p> <p><b>Update:</b> fixed const correctness.</p> <p><b>PS:</b> There's also an <a href="http://coliru.stacked-crooked.com/view?id=665ae867f4fd7a82d9c8ff461c46dcb6" rel="nofollow">asynchronous variant</a>.</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload