Sanich
Sanich

Reputation: 1835

Forcing class methods use setter/getter of its own private member

Below is a very simple example of a class. This class is used in a multi-threaded system and I want to ensure that every access to _x (also in a future extensions of the class by other developers) will be protected by mutex. One way doing so, is to put the mutex in the setter and getter and enforce using them also from the class methods, meaning, any direct access will generate a compilation error. Is it possible?

class Myclass
{
public:
   int getX() const
   {
      boost::mutex::scoped_lock lock(_lock);
      return _x;
   }

   void setX(int x)
   {
      boost::mutex::scoped_lock lock(_lock);
      _x = x;
   }

   void foo()
   {
      //accessing _x; 
   }
private:
   mutable boost::mutex _lock;
   int _x;
};

Upvotes: 2

Views: 271

Answers (2)

luk32
luk32

Reputation: 16070

You cannot prevent class from accessing its members, which makes sense; how would you allow setter and getter to do it?

But you have a nice semantic concept of a guarded property. I would suggest making a template class like locked_variable<T> which encapsulates such a property. The original property would be private, and setter and getter would be public.

Something like:

template <typename T>
class locked_property {
public:
  locked_property(boost::mutex& lock) : _lock(lock) {}

  void set(const &T value) {
    boost::mutex::scoped_lock lock(_lock);
    _val = value;
  }

  // you return a copy, maybe a reference or const ref should be used here
  T get() {
    boost::mutex::scoped_lock lock(_lock);
    return _val;
  }

private:
  boost::mutex& _lock;
  T val;
}

Then use it in MyClass. Depending on your needs maybe a move-setter would be appropriate.

Upvotes: 3

Bathsheba
Bathsheba

Reputation: 234715

You can't do this directly.

One approach would be to create a base class MyBaseClass which has the member _x marked private and code the accessors, along with the mutual exclusion object, in MyBaseClass.

Then define class Myclass : public MyBaseClass

In your specific case though, using the considerably simpler std::atomic<int> _x might be adequate.

Upvotes: 5

Related Questions