Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to make derived class do actions before calling base class?

Tags:

c++

Before anything: I'm not a developer and I might not understand some of your messages, and as English is not my native language my question could be hard to understand.

Considering :

class MyVector  
{
    std::vector<command> vec;
    std::mutex vector_m;

public:
    void MVpush_back(command t)
    {
        this->vector_m.lock();
        this->vec.push_back(t);
        this->vector_m.unlock();
    }

};

command is a custom class (its content doesn't seem relevant here; copy constructor does exist).

Basically, as I have a lot of possible writer & readers, thus I want to force the use of the mutex to access to the vec parameter.

As I'll only use push_back(), erase() and find() I could redefine them, but I was wondering if there is a way not have to redefine all functions.

something like:

 <template> safe(*function name*<template>)
 {
   this->vector_m.lock();
   <template> retval = vec.*function name*<parameter>;
   this->vector_m.unlock();
   return retval;
 }

where the function to call is a kind of parameter...

I thought it could be done using std::initializer_list<type> but the type requirement is blocking.

Is there a way to do such a thing?

Rephrased question: is there a way to push a function with parameter(1) as parameter of a function(2) and make function(2) call function(1) ?

like image 556
A.albin Avatar asked Aug 03 '17 09:08

A.albin


1 Answers

If you don't mind sacrificing the use of the member access operator (.), you can wrap all the vector operations neatly into lockable operations.

class MyVector {
  std::vector<command> vec;
  std::mutex vector_m;

  struct locker {
    MyVector& _ref;
    locker(MyVector& parent) : _ref(parent) {
      _ref.vector_m.lock();
    }
    ~locker() { _ref.vector_m.unlock(); }

    std::vector<command>* operator->() && { return &_ref.vec; }
  };

  public:
    locker operator->() { return {*this}; }
};

Now, every access to the underlying vector will lock and unlock the vector for the duration of the operation:

MyVector mv;
mv->push_back(/* ... */);
// This locks the mutex before doing the push back
// And unlocks it immediately after, even in the face of exceptions.

The magic is in operator-> acting in a transitive manner. It is applied to the return value of itself until a regular pointer is returned, which is then accessed as usual. But every temporary along the way is created and destroyed in LIFO order. So the temporary MyVector::locker object has a lifetime that is just the duration of the access more or less.

like image 50
StoryTeller - Unslander Monica Avatar answered Nov 09 '22 22:11

StoryTeller - Unslander Monica