C++惯用法 lock_proxy

arthur 在其名篇arrow_proxy中详细描述了如何使用arrow_proxy解决zip_view的reference生存期的问题。bjarne和andrei描述过lock_proxy,用于实现lock_ptr:

#include <mutex>
#include <iostream>
template<class Pointer,class Mutex>
struct lock_proxy {
    Pointer r;
    std::scoped_lock<Mutex> l;
    lock_proxy(Pointer rp,Mutex* m):r(rp),l(*m){}
    Pointer operator->() {
        return r;
    }
};
struct A{
    typedef std::mutex Mutex;
    Mutex m;
    void foo()
    {
        std::cout<<"world\n";
    }
};
template<class T>
struct LockPtr{
    typedef typename T::Mutex M;
    T* r;
    M* m;
    lock_proxy<T*, std::mutex> operator->(){
        return lock_proxy<T*, std::mutex> (r,m);
    }
};
int main()
{
    A a;
    LockPtr<A> lptr{&a,&a.m};
    lptr->foo();
}

上述代码例子中,LockPtr 使用A类型对象a的指针和a的互斥锁成员m的指针初始化,lptr->foo()时会借用lockproxy类型的临时对象的构造函数加锁,然后调用foo()函数,调用结束后整个表达式lptr->foo()完成evaluation,lockproxy临时对象生存期结束,释放锁。lockproxy和通用的arrow_proxy略有不同,arrow_proxy中主要用来借助成员变量reference实现对zip_view等的reference的存在进行支持,而lockproxy主要借助临时对象的RAII在构造函数使用其成员scoped_lock加锁,在析构函数使用成员scoped_lock解锁。非常灵巧的惯用法。

Posted 2022-04-18