挖井

类库大魔王的挖井日记

挖一口属于自己的井


C++中RAII的实现手法

Go语言中有defer可以在退出当前作用域时执行一个函数调用,C++中以前常用的做法是创建一个类的对象,在该类的析构函数中写入需要执行的代码。而这个对象可以创建在栈中,也可以放在std::auto_prt<>std::unique_prt<>之类的地方,只要退出作用域就会被销毁就可以。这在网上能找到不少的讨论,比如C++之父的这段,C++ Core Guidelines中的这段,以及Cpp Reference中的这篇

Boost中也提供了BOOST_SCOPE_EXIT宏,但是用起来相当丑陋,而且像稍早版本的Qt Creator内置的简单的C++语法解析器甚至不能正常解析:

{ // Some local scope.
    ...
    BOOST_SCOPE_EXIT(capture_list) {
        ... // Body code.
    } BOOST_SCOPE_EXIT_END
    ...
}

到了C++11,这个宏有了改进,使用lambda的机制:

void world::add_person(person const& a_person) {
    persons_.push_back(a_person);

    // This block must be no-throw.
    person& p = persons_.back();
    person::evolution_t checkpoint = p.evolution;
    // Capture all by reference `&`, but `checkpoint` and `this` (C++11 only).
    BOOST_SCOPE_EXIT_ALL(&, checkpoint, this) { // Use `this` (not `this_`).
        if(checkpoint == p.evolution) this->persons_.pop_back();
    }; // Use `;` (not `SCOPE_EXIT_END`).

    // ...

    checkpoint = ++p.evolution;

    // Assign new identifier to the person.
    person::id_t const prev_id = p.id;
    p.id = next_id_++;
    // Capture all by value `=`, but `p` (C++11 only).
    BOOST_SCOPE_EXIT_ALL(=, &p) {
        if(checkpoint == p.evolution) {
            this->next_id_ = p.id;
            p.id = prev_id;
        }
    };

    // ...

    checkpoint = ++p.evolution;
}

既然这样,其实我们自己也不是一定要用Boost的实现,可以自己简单实现一个:

#include <functional>

class ScopedGuard
{
    std::function<void(void)> m_f;
public:
    ScopedGuard() = delete;
    ScopedGuard(ScopedGuard&&) =delete;
    ScopedGuard(const ScopedGuard&) =delete;
    ScopedGuard& operator=(ScopedGuard&&)=delete;
    ScopedGuard& operator=(const ScopedGuard&)=delete;
    ScopedGuard(std::function<void(void)> f) : m_f(f) {}
    ~ScopedGuard() { m_f(); }
};

使用示例:

ScopedGuard queryMutexUnlock([this](){m_queryMutex.unlock();});

ScopedGuard postFinishedQueryEvent([this, e](){QCoreApplication::postEvent(this, e);});

有了lambda就是方便。

本文地址:

https://minidump.info/blog/2019/04/raii-in-cpp/

感觉本文不错,不妨小额鼓励我一下!
上一篇

SQLCipher Android平台升级踩坑

公司项目里使用SQLCipher用于本地加密存储数据,之前发现在iOS上打开数据库后执行第一条CRUD特别慢,经过几番优化尝试,发现只要在编译选项指定使用Apple Common Crypto,就能比使用OpenSSL提升100倍性能。但是Android平台上也只能使用OpenSSL,性能问题...…

Job 全文阅读
下一篇

胎动计数器app

自从知道怀孕28周起要数胎动,我就花了几天时间写了个简单的app给老婆数胎动用。App的功能相当的简单,启动后主界面是一个大大的圆形按钮,用户点击该按钮便是记录一次胎动。除此之外,还有每日的胎动记录报告,以及几日来的胎动记录以折线图、柱状图等方式的图表显示,并将报告或图表分享到其他app,还有...…

Shareware 全文阅读