C++资源管理与RAII编程范式
C++资源管理与RAII编程范式
资源获取即初始化(RAII,Resource Acquisition Is Initialization)是C++中最重要的编程范式之一。它通过对象的生命周期来管理资源,确保资源在对象构造时获取,在对象析构时释放。这种机制不仅适用于内存管理,还可以管理文件句柄、网络连接、互斥锁等各种资源。
RAII的核心思想是将资源的生命周期与对象的生命周期绑定。当对象离开作用域时,无论是正常返回还是异常抛出,析构函数都会被自动调用,从而保证资源被正确释放。这种自动化的资源管理机制大大降低了资源泄漏的风险。
#include
#include
#include
#include
#include
class FileHandle {
std::FILE* file_;
std::string filename_;
public:
explicit FileHandle(const std::string& filename, const char* mode)
: filename_(filename) {
file_ = std::fopen(filename.c_str(), mode);
if (!file_) {
throw std::runtime_error("Failed to open file: " + filename);
}
std::cout << "File opened: " << filename_ << std::endl;
}
~FileHandle() {
if (file_) {
std::fclose(file_);
std::cout << "File closed: " << filename_ << std::endl;
}
}
FileHandle(const FileHandle&) = delete;
FileHandle& operator=(const FileHandle&) = delete;
FileHandle(FileHandle&& other) noexcept
: file_(other.file_), filename_(std::move(other.filename_)) {
other.file_ = nullptr;
}
FileHandle& operator=(FileHandle&& other) noexcept {
if (this != &other) {
if (file_) {
std::fclose(file_);
}
file_ = other.file_;
filename_ = std::move(other.filename_);
other.file_ = nullptr;
}
return *this;
}
std::FILE* get() const { return file_; }
bool write(const std::string& data) {
if (!file_) return false;
return std::fwrite(data.c_str(), 1, data.size(), file_) == data.size();
}
std::string read_all() {
if (!file_) return "";
std::fseek(file_, 0, SEEK_END);
long size = std::ftell(file_);
std::fseek(file_, 0, SEEK_SET);
std::string buffer(size, '\0');
std::fread(&buffer[0], 1, size, file_);
return buffer;
}
};
void file_operations_example() {
try {
FileHandle file("test.txt", "w");
file.write("Hello, RAII!\n");
file.write("Resource management is automatic.\n");
} catch (const std::exception& e) {
std::cerr << "Error: " << e.what() << std::endl;
}
}
智能指针是RAII原则在内存管理中的典型应用。std::unique_ptr提供独占所有权语义,而std::shared_ptr提供共享所有权语义。
template
class UniquePtr {
T* ptr_;
public:
explicit UniquePtr(T* ptr = nullptr) : ptr_(ptr) {}
~UniquePtr() {
delete ptr_;
}
UniquePtr(const UniquePtr&) = delete;
UniquePtr& operator=(const UniquePtr&) = delete;
UniquePtr(UniquePtr&& other) noexcept : ptr_(other.ptr_) {
other.ptr_ = nullptr;
}
UniquePtr& operator=(UniquePtr&& other) noexcept {
if (this != &other) {
delete ptr_;
ptr_ = other.ptr_;
other.ptr_ = nullptr;
}
return *this;
}
T* get() const { return ptr_; }
T* release() {
T* temp = ptr_;
ptr_ = nullptr;
return temp;
}
void reset(T* ptr = nullptr) {
delete ptr_;
ptr_ = ptr;
}
T& operator*() const { return *ptr_; }
T* operator->() const { return ptr_; }
explicit operator bool() const { return ptr_ != nullptr; }
};
template
UniquePtr make_unique(Args&&... args) {
return UniquePtr(new T(std::forward(args)...));
}
class Resource {
int id_;
std::vector data_;
public:
explicit Resource(int id, size_t size = 1000)
: id_(id), data_(size, id) {
std::cout << "Resource " << id_ << " constructed" << std::endl;
}
~Resource() {
std::cout << "Resource " << id_ << " destroyed" << std::endl;
}
void process() {
std::cout << "Processing resource " << id_
<< " with " << data_.size() << " elements" << std::endl;
}
int get_id() const { return id_; }
};
void smart_pointer_example() {
auto res1 = make_unique(1, 500);
res1->process();
std::unique_ptr res2 = std::make_unique(2, 1000);
res2->process();
std::shared_ptr shared1 = std::make_shared(3);
{
std::shared_ptr shared2 = shared1;
std::cout << "Reference count: " << shared1.use_count() << std::endl;
shared2->process();
}
std::cout << "Reference count after scope: " << shared1.use_count() << std::endl;
}
锁的管理也是RAII的重要应用场景。std::lock_guard和std::unique_lock确保互斥量在作用域结束时自动释放。
class ThreadSafeCounter {
mutable std::mutex mutex_;
int value_;
public:
ThreadSafeCounter() : value_(0) {}
void increment() {
std::lock_guard lock(mutex_);
++value_;
}
void add(int delta) {
std::lock_guard lock(mutex_);
value_ += delta;
}
int get() const {
std::lock_guard lock(mutex_);
return value_;
}
bool compare_and_set(int expected, int new_value) {
std::lock_guard lock(mutex_);
if (value_ == expected) {
value_ = new_value;
return true;
}
return false;
}
};
template
class LockGuard {
Mutex& mutex_;
bool locked_;
public:
explicit LockGuard(Mutex& mutex) : mutex_(mutex), locked_(true) {
mutex_.lock();
}
~LockGuard() {
if (locked_) {
mutex_.unlock();
}
}
LockGuard(const LockGuard&) = delete;
LockGuard& operator=(const LockGuard&) = delete;
};
template
class UniqueLock {
Mutex* mutex_;
bool locked_;
public:
UniqueLock() : mutex_(nullptr), locked_(false) {}
explicit UniqueLock(Mutex& mutex) : mutex_(&mutex), locked_(true) {
mutex_->lock();
}
~UniqueLock() {
if (locked_) {
mutex_->unlock();
}
}
UniqueLock(const UniqueLock&) = delete;
UniqueLock& operator=(const UniqueLock&) = delete;
UniqueLock(UniqueLock&& other) noexcept
: mutex_(other.mutex_), locked_(other.locked_) {
other.mutex_ = nullptr;
other.locked_ = false;
}
UniqueLock& operator=(UniqueLock&& other) noexcept {
if (this != &other) {
if (locked_) {
mutex_->unlock();
}
mutex_ = other.mutex_;
locked_ = other.locked_;
other.mutex_ = nullptr;
other.locked_ = false;
}
return *this;
}
void lock() {
if (!mutex_) throw std::system_error();
mutex_->lock();
locked_ = true;
}
void unlock() {
if (!locked_) throw std::system_error();
mutex_->unlock();
locked_ = false;
}
bool owns_lock() const { return locked_; }
};
自定义资源管理器可以封装各种系统资源,如数据库连接、网络套接字等。
class DatabaseConnection {
int connection_id_;
bool connected_;
void connect() {
std::cout << "Connecting to database..." << std::endl;
connected_ = true;
}
void disconnect() {
if (connected_) {
std::cout << "Disconnecting from database..." << std::endl;
connected_ = false;
}
}
public:
explicit DatabaseConnection(int id) : connection_id_(id), connected_(false) {
connect();
}
~DatabaseConnection() {
disconnect();
}
DatabaseConnection(const DatabaseConnection&) = delete;
DatabaseConnection& operator=(const DatabaseConnection&) = delete;
DatabaseConnection(DatabaseConnection&& other) noexcept
: connection_id_(other.connection_id_), connected_(other.connected_) {
other.connected_ = false;
}
void execute_query(const std::string& query) {
if (!connected_) {
throw std::runtime_error("Not connected to database");
}
std::cout << "Executing query: " << query << std::endl;
}
void begin_transaction() {
execute_query("BEGIN TRANSACTION");
}
void commit() {
execute_query("COMMIT");
}
void rollback() {
execute_query("ROLLBACK");
}
};
class Transaction {
DatabaseConnection& conn_;
bool committed_;
public:
explicit Transaction(DatabaseConnection& conn)
: conn_(conn), committed_(false) {
conn_.begin_transaction();
}
~Transaction() {
if (!committed_) {
try {
conn_.rollback();
} catch (...) {
}
}
}
void commit() {
conn_.commit();
committed_ = true;
}
Transaction(const Transaction&) = delete;
Transaction& operator=(const Transaction&) = delete;
};
void database_transaction_example() {
try {
DatabaseConnection db(1);
Transaction txn(db);
db.execute_query("INSERT INTO users VALUES (1, 'Alice')");
db.execute_query("INSERT INTO users VALUES (2, 'Bob')");
txn.commit();
} catch (const std::exception& e) {
std::cerr << "Transaction failed: " << e.what() << std::endl;
}
}
作用域守卫是一种通用的RAII模式,可以在作用域结束时执行任意清理操作。
template
class ScopeGuard {
Func cleanup_;
bool active_;
public:
explicit ScopeGuard(Func cleanup)
: cleanup_(std::move(cleanup)), active_(true) {}
~ScopeGuard() {
if (active_) {
cleanup_();
}
}
void dismiss() {
active_ = false;
}
ScopeGuard(const ScopeGuard&) = delete;
ScopeGuard& operator=(const ScopeGuard&) = delete;
ScopeGuard(ScopeGuard&& other) noexcept
: cleanup_(std::move(other.cleanup_)), active_(other.active_) {
other.active_ = false;
}
};
template
ScopeGuard make_scope_guard(Func cleanup) {
return ScopeGuard(std::move(cleanup));
}
#define SCOPE_GUARD_CONCAT_IMPL(x, y) x##y
#define SCOPE_GUARD_CONCAT(x, y) SCOPE_GUARD_CONCAT_IMPL(x, y)
#define SCOPE_EXIT(code) \
auto SCOPE_GUARD_CONCAT(scope_guard_, __LINE__) = make_scope_guard([&]() { code; })
void scope_guard_example() {
int* buffer = new int[100];
SCOPE_EXIT(delete[] buffer);
std::FILE* file = std::fopen("data.txt", "r");
if (!file) return;
SCOPE_EXIT(std::fclose(file));
bool success = false;
auto guard = make_scope_guard([&]() {
if (!success) {
std::cout << "Operation failed, cleaning up..." << std::endl;
}
});
std::cout << "Performing operations..." << std::endl;
success = true;
guard.dismiss();
}
内存池是另一个RAII应用的例子,它管理一块预分配的内存区域。
class MemoryPool {
std::vector buffer_;
size_t offset_;
public:
explicit MemoryPool(size_t size) : buffer_(size), offset_(0) {
std::cout << "Memory pool created: " << size << " bytes" << std::endl;
}
~MemoryPool() {
std::cout << "Memory pool destroyed, used: " << offset_
<< " / " << buffer_.size() << " bytes" << std::endl;
}
void* allocate(size_t size, size_t alignment = alignof(std::max_align_t)) {
size_t padding = (alignment - (offset_ % alignment)) % alignment;
size_t required = padding + size;
if (offset_ + required > buffer_.size()) {
throw std::bad_alloc();
}
void* ptr = &buffer_[offset_ + padding];
offset_ += required;
return ptr;
}
void reset() {
offset_ = 0;
}
size_t used() const { return offset_; }
size_t available() const { return buffer_.size() - offset_; }
};
template
class PoolAllocator {
MemoryPool* pool_;
public:
using value_type = T;
explicit PoolAllocator(MemoryPool& pool) : pool_(&pool) {}
template
PoolAllocator(const PoolAllocator& other) : pool_(other.pool_) {}
T* allocate(size_t n) {
return static_cast(pool_->allocate(n * sizeof(T), alignof(T)));
}
void deallocate(T*, size_t) {
}
template
struct rebind {
using other = PoolAllocator;
};
template
friend class PoolAllocator;
};
void memory_pool_example() {
MemoryPool pool(1024 * 1024);
std::vector> vec(PoolAllocator(pool));
for (int i = 0; i < 100; ++i) {
vec.push_back(i);
}
std::cout << "Pool usage: " << pool.used() << " bytes" << std::endl;
pool.reset();
std::cout << "Pool reset, available: " << pool.available() << " bytes" << std::endl;
}
异常安全是RAII的重要保证。通过RAII,即使在异常发生时,资源也能被正确释放。
class ExceptionSafeOperation {
std::vector> resources_;
public:
void add_resource(int id) {
auto res = std::make_unique(id);
res->process();
resources_.push_back(std::move(res));
}
void perform_operation(bool should_fail = false) {
add_resource(1);
add_resource(2);
if (should_fail) {
throw std::runtime_error("Operation failed");
}
add_resource(3);
}
size_t resource_count() const {
return resources_.size();
}
};
void exception_safety_example() {
try {
ExceptionSafeOperation op;
op.perform_operation(true);
} catch (const std::exception& e) {
std::cout << "Caught exception: " << e.what() << std::endl;
std::cout << "All resources cleaned up automatically" << std::endl;
}
}
资源句柄的转移语义允许资源所有权在对象之间安全转移。
template
class ResourceHandle {
Resource* resource_;
void release_resource() {
if (resource_) {
delete resource_;
resource_ = nullptr;
}
}
public:
explicit ResourceHandle(Resource* res = nullptr) : resource_(res) {}
~ResourceHandle() {
release_resource();
}
ResourceHandle(const ResourceHandle&) = delete;
ResourceHandle& operator=(const ResourceHandle&) = delete;
ResourceHandle(ResourceHandle&& other) noexcept : resource_(other.resource_) {
other.resource_ = nullptr;
}
ResourceHandle& operator=(ResourceHandle&& other) noexcept {
if (this != &other) {
release_resource();
resource_ = other.resource_;
other.resource_ = nullptr;
}
return *this;
}
Resource* get() const { return resource_; }
Resource* operator->() const { return resource_; }
Resource& operator*() const { return *resource_; }
Resource* release() {
Resource* temp = resource_;
resource_ = nullptr;
return temp;
}
void reset(Resource* res = nullptr) {
release_resource();
resource_ = res;
}
explicit operator bool() const { return resource_ != nullptr; }
};
std::vector> create_resources(int count) {
std::vector> handles;
for (int i = 0; i < count; ++i) {
handles.push_back(ResourceHandle(new Resource(i)));
}
return handles;
}
RAII与现代C++特性结合,可以实现更加优雅的资源管理。
class AsyncOperation {
std::unique_ptr thread_;
std::atomic running_;
public:
template
explicit AsyncOperation(Func&& func) : running_(true) {
thread_ = std::make_unique([this, f = std::forward(func)]() {
while (running_.load()) {
f();
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
});
}
~AsyncOperation() {
running_.store(false);
if (thread_ && thread_->joinable()) {
thread_->join();
}
}
AsyncOperation(const AsyncOperation&) = delete;
AsyncOperation& operator=(const AsyncOperation&) = delete;
void stop() {
running_.store(false);
}
};
void async_operation_example() {
{
AsyncOperation op([]() {
std::cout << "Background task running..." << std::endl;
});
std::this_thread::sleep_for(std::chrono::seconds(1));
}
std::cout << "AsyncOperation destroyed, thread joined automatically" << std::endl;
}
RAII原则不仅适用于资源管理,还可以用于状态管理和行为控制。
class StateGuard {
bool& flag_;
bool old_value_;
public:
explicit StateGuard(bool& flag, bool new_value)
: flag_(flag), old_value_(flag) {
flag_ = new_value;
}
~StateGuard() {
flag_ = old_value_;
}
StateGuard(const StateGuard&) = delete;
StateGuard& operator=(const StateGuard&) = delete;
};
class Logger {
bool verbose_;
public:
Logger() : verbose_(false) {}
void set_verbose(bool v) { verbose_ = v; }
bool is_verbose() const { return verbose_; }
void log(const std::string& msg) {
if (verbose_) {
std::cout << "[VERBOSE] " << msg << std::endl;
} else {
std::cout << "[INFO] " << msg << std::endl;
}
}
};
void state_guard_example() {
Logger logger;
logger.log("Normal logging");
{
StateGuard guard(const_cast(logger.is_verbose()), true);
logger.log("Detailed logging");
logger.log("More details");
}
logger.log("Back to normal");
}
通过RAII,我们可以确保资源管理的正确性和异常安全性。这种编程范式是C++区别于其他语言的重要特性,也是编写健壮C++代码的基础。掌握RAII不仅能避免资源泄漏,还能让代码更加简洁和易于维护。在现代C++开发中,应该始终优先考虑使用RAII来管理资源,而不是手动管理资源的生命周期。
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐



所有评论(0)