RAII:资源获取即初始化
什么是RAII?
RAII,全称为Resource Acquisition Is Initialization,由C++之父Bjarne Stroustrup提出,中文翻译为“资源获取即初始化”。Stroustrup说:“使用局部对象来管理资源的技术称为资源获取即初始化。” 这里的资源主要是指操作系统中的有限资源,如内存、网络套接字等。局部对象是指存储在栈上的对象,其生命周期由操作系统管理,无需人工介入。
RAII的原理
资源的使用一般经历以下三个步骤:
- 获取资源
- 使用资源
- 销毁资源
然而,资源的销毁常常是程序员容易忽略的一个环节。为了让资源自动销毁,Bjarne Stroustrup提出了RAII方案。它充分利用了C++语言中局部对象自动销毁的特性来控制资源的生命周期。
下面我们通过一个简单的例子来看一下局部对象的自动销毁特性:
#include <iostream>
using namespace std;
class person {
public:
person(const std::string name = "", int age = 0) :
name_(name), age_(age) {
std::cout << "Init a person!" << std::endl;
}
~person() {
std::cout << "Destroy a person!" << std::endl;
}
const std::string& getname() const {
return this->name_;
}
int getage() const {
return this->age_;
}
private:
const std::string name_;
int age_;
};
int main() {
person p;
return 0;
}
编译并运行:
g++ person.cpp -o person
./person
运行结果:
Init a person!
Destroy a person!
从person
类可以看出,当我们在main
函数中声明一个局部对象时,会自动调用构造函数进行对象的初始化。当main
函数执行完成后,自动调用析构函数来销毁对象。整个过程无需人工介入,由操作系统自动完成。因此,在使用资源时,我们可以在构造函数中进行初始化,在析构函数中进行销毁。
RAII的步骤
RAII过程可以总结为以下四个步骤:
- 设计一个类封装资源。
- 在构造函数中初始化资源。
- 在析构函数中销毁资源。
- 使用时声明一个该类的对象。
RAII的应用
为了更好地理解RAII的应用,我们通过一个简单的例子来说明如何将RAII应用到实际代码中。在Linux下,经常会使用多线程技术,而多线程中不可避免地会用到互斥锁。互斥锁用于保护临界资源,使其一次只被一个线程访问。我们可以封装POSIX标准的互斥锁来实现RAII。
#include <pthread.h>
#include <iostream>
class Mutex {
public:
Mutex() {
pthread_mutex_init(&mutex_, nullptr);
}
~Mutex() {
pthread_mutex_destroy(&mutex_);
}
void lock() {
pthread_mutex_lock(&mutex_);
}
void unlock() {
pthread_mutex_unlock(&mutex_);
}
private:
pthread_mutex_t mutex_;
};
class LockGuard {
public:
LockGuard(Mutex& mutex) : mutex_(mutex) {
mutex_.lock();
}
~LockGuard() {
mutex_.unlock();
}
private:
Mutex& mutex_;
};
void* threadFunc(void* arg) {
Mutex* mutex = static_cast<Mutex*>(arg);
LockGuard lock(*mutex);
// 在此处使用临界资源
std::cout << "Thread is running..." << std::endl;
return nullptr;
}
int main() {
Mutex mutex;
pthread_t thread;
pthread_create(&thread, nullptr, threadFunc, &mutex);
pthread_join(thread, nullptr);
return 0;
}
在这个例子中,Mutex
类封装了互斥锁的初始化和销毁,LockGuard
类则利用RAII技术在构造函数中锁定互斥锁,并在析构函数中解锁。这确保了互斥锁在任何情况下都能被正确解锁,而无需手动干预。
总结
RAII是一种强大的资源管理技术,通过在对象的生命周期中自动管理资源的获取和释放,提高了代码的安全性和可维护性。通过封装资源、在构造函数中初始化、在析构函数中销毁,我们可以确保资源在正确的时间点被释放,从而减少资源泄漏和其他潜在问题。