C++ 中使用 RAII 的注意事项

Aug 20, 2022 • 预计阅读时间 1 分钟

RAII (Resource Acquisition Is Initialization) 翻译为中文是「资源获取即初始化」。

通常用来做局部资源清理或者防止忘记解锁导致死锁:

class LockGuard {
public:
    LockGuard() { lock(); }
    ~LockGuard() { unlock(); }

private:
    static pthread_mutex_t _fastmutex;

    void lock() {
        pthread_mutex_lock(&_fastmutex);
    }

    void unlock() {
        pthread_mutex_unlock(&_fastmutex);
    }
};

pthread_mutex_t LockGuard::_fastmutex(PTHREAD_MUTEX_INITIALIZER);

以上代码定义了一个局部锁,锁生效的域和这个类的生命周期所在域一致。

在 C++ 里,如果 LockGuard 使用方式不对会导致锁无效:

错误的代码:

void foo() {
    // 生成的是匿名对象
    LockGuard(); // 匿名对象在这行代码之后就被释放,锁也就无效了
}

匿名对象的生命周期很短,超出它所在行就会被析构,所以正确的做法是使用具名的局部变量。

正确的代码:

void foo() {
    // 具名的局部对象,生命周期是它所在的作用域
    LockGuard _guard_;
}

另外,不用担心没有被引用的局部对象会被编译器优化,编译器足够聪明,会根据类的构造/析构方法是否为空来判断要不要保留这个局部对象。

参考资源

https://rules.sonarsource.com/cpp/RSPEC-5184

C++
版权声明:如果转发请带上本文链接和注明来源。

lvv.me

iOS/macOS Developer

使用 spctl 检查 App 的来源

Git 的稀疏检出(Sparse checkout)功能