How to force a derived class to perform actions before calling the base class?

First of all: I am not a developer, and I do not understand some of your posts, and since English is not my native language, my question can be difficult 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 - this is a custom class (its contents do not make sense here, the copy constructor exists).

In principle, since I have many possible writers and readers, so I want to force to use mutexto access the parameter vec.

Since I will use only push_back(), erase()and find(), I could redefine them, but I was wondering if there is a way to redefine all functions.

sort of:

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

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

, std::initializer_list<type>, .

?

: (1) (2) (2) (1)?

+6
4

(.), .

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}; }
};

:

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.

operator->, . , , , . LIFO. , MyVector::locker , .

+4

, ; ; -, .

template<class T>
class OverkillProtector {
private:
    T& d;
    std::unique_lock<std::mutex>lock ;

public:
    OverkillProtector(T& d_, std::mutex& m_) :
        d(d_),
        lock(m_)
    {}
    OverkillProtector(const OverkillProtector&) = delete;
    OverkillProtector& operator =(const OverkillProtector&) = delete;

    T& getValue() { return d; }
    const T& getValue() const { return d; }
};

, ( ) , . , , , .

0

:

class MyVector
{
    std::vector<command> vec;
    mutable std::mutex vector_m;
public:
    template <typename R, typename ... T, typename ... P>
    R safeCall(R (std::vector<command>::*f)(T ...), P&& ... p)
    {
        std::lock_guard<std::mutex> l(vector_m);
        return (vec.*f)(std::forward<P>(p)...);
    }
    template <typename R, typename ... T, typename ... P>
    R safeCall(R (std::vector<command>::*f)(T ...) const, P&&  ... p) const
    {
        std::lock_guard<std::mutex> l(vector_m);
        return (vec.*f)(std::forward<P>(p)...);
    }
};

void test()
{
    MyVector v;
    v.safeCall(&std::vector<int>::push_back, 7);
    MyVector const* vv = &v;
    int n = vv->safeCall(&std::vector<int>::operator[], 0);
}

, , – typedef , ... ?

#define safe_call(V, R, F, ...) V R safeCall(&std::vector<int>::F, ## __VA_ARGS__)
safe_call(v, ., push_back, 7);
safe_call(vv, ->, operator[], 1);

:

#define safe_call(V, F, ...) V safeCall(&std::vector<int>::F, ## __VA_ARGS__)
safe_call(v., push_back, 7);
safe_call(vv->, operator[], 1);

, , ...

, - :

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

    template <typename R, typename ... T>
    R safeCall(R (std::vector<command>::*f)(T...), T... t)
    {
        std::lock_guard<std::mutex> l(vector_m);
        return (vec.*f)(t...);
    }
    // const variant, too
public:
    // ...
};

void MyVector::push_back(Command t)
{
    safeCall(&std::vector<Command>::push_back, t);
}
0

- :

class MyVector  
{
    std::vector<command> vec;
    std::mutex vector_m;
public:
    template <typename F>
    decltype(auto) Do(F&& f)
    {
        std::unique_lock<std::mutex> lock{vector_m};
        return std::forward<F>(f)(vec);
    }
};

Using similarly:

MyVector myVector;
command myCommand;

myVector.Do([&](auto& vec) { vec.push_back(myCommand); });
0
source

All Articles