首页 > 其他分享 >RAII思想

RAII思想

时间:2024-09-10 22:24:12浏览次数:9  
标签:std 思想 RAII 互斥 mutex LockGuard 资源

c++ RAII思想

什么是RAII

资源获取即初始化(Resource Acquisition Is Initialization,简称 RAII)是一种 C++ 编程技术,它将在使用前获取(分配的堆内存、执行线程、打开的套接字、打开的文件、锁定的互斥量、磁盘空间、数据库连接等有限资源)的资源的生命周期与某个对象的生命周期绑定在一起。

确保在控制对象的生命周期结束时,按照资源获取的相反顺序释放所有资源。同样,如果资源获取失败(构造函数退出并带有异常),则按照初始化的相反顺序释放所有已完全构造的成员和基类子对象所获取的资源。

这利用了核心语言特性(对象生命周期、作用域退出、初始化顺序和堆栈展开),以消除资源泄漏并确保异常安全。

RAII 的原理

RAII的核心思想就是:利用栈上局部变量的自动析构来保证资源一定会被释放

因为我们平常 C++ 编程过程中,经常会忘了释放资源,比如申请的堆内存忘了手动释放,那么就会导致内存泄露。

还有一些常见是程序遇到了异常,提前终止了,我们的资源也来不及释放。

但是变量的析构函数的调用是由编译器保证的一定会被执行,所以如果资源的获取和释放与对象的构造和析构绑定在一起,就不会有各种资源泄露问题。

RAII 类实现步骤

一般设计实现一个 RAII 类需要四个步骤:

  • 设计一个类封装资源,资源可以是内存、文件、socket、锁等等一切
  • 在构造函数中执行资源的初始化,比如申请内存、打开文件、申请锁
  • 在析构函数中执行销毁操作,比如释放内存、关闭文件、释放锁
  • 使用时声明一个该对象的类,一般在你希望的作用域声明即可,比如在函数开始,或者作为类的成员变量

实例

下面写一个 RAII 示例,用来演示使用 RAII 思想包装文件的操作,假设我们需要在程序中使用一个文件:

#include <iostream>
#include <fstream>

int main() {
    std::ifstream myfile("example.txt"); // 换自己的文件路径
    if (myfile.is_open()) {
        std::cout << "File is opened." << std::endl;
        // do some work with the file
    }
    else {
        std::cout << "Failed to open the file." << std::endl;
    }
    myfile.close();
    return 0;
}

上面这个例子中,手动打开和关闭了文件。

如果在程序执行的过程中发生了异常或者程序提前退出,可能会导致文件没有被关闭,从而产生资源未释放等问题。

现在使用 RAII 来改进这个例子,通过定义一个包含文件句柄的类,在类的构造函数中打开文件,在析构函数中关闭文件:

#include <iostream>
#include <fstream>

class File {
public:
    File(const char* filename) : m_handle(std::ifstream(filename)) {}
    ~File() {
        if (m_handle.is_open()) {
            std::cout << "File is closed." << std::endl;
            m_handle.close();
        }
    }

    std::ifstream& getHandle() {
        return m_handle;
    }

private:
    std::ifstream m_handle;
};

int main() {
    File myfile("example.txt");
    if (myfile.getHandle().is_open()) {
        std::cout << "File is opened." << std::endl;
        // do some work with the file
    }
    else {
        std::cout << "Failed to open the file." << std::endl;
    }
    return 0;
}

这样,在程序退出时,File类的析构函数会自动被调用,从而自动关闭文件,即使程序提前退出或者发生异常,也不会产生内存泄漏等问题.

用 RAII 思想包装 mutex

在 C++ 中,可以使用 RAII 思想来包装 mutex,确保在多线程编程中始终能安全锁定和解锁互斥量,这个用得非常多,可以在很多开源项目中看到这样的包装。

#include <iostream>
#include <mutex>
#include <thread>

class LockGuard {
public:
    explicit LockGuard(std::mutex &mtx) : mutex_(mtx) {
        mutex_.lock();
    }

    ~LockGuard() {
        mutex_.unlock();
    }

    // 禁止复制
    LockGuard(const LockGuard &) = delete;
    LockGuard &operator=(const LockGuard &) = delete;

private:
    std::mutex &mutex_;
};

// 互斥量
std::mutex mtx;
// 多线程操作的变量
int shared_data = 0;

void increment() {
    for (int i = 0; i < 10000; ++i) {
        // 申请锁
        LockGuard lock(mtx);
        ++shared_data;
        // 作用域结束后会析构 然后释放锁
    }
}

int main() {
    std::thread t1(increment);
    std::thread t2(increment);

    t1.join();
    t2.join();

    std::cout << "Shared data: " << shared_data << std::endl;

    return 0;
}

上面定义了一个 LockGuard 类,该类在构造函数中接收一个互斥量(mutex)引用并对其进行锁定,在析构函数中对互斥量进行解锁。

这样,我们可以将互斥量传递给 LockGuard 对象,并在需要保护的代码块内创建该对象,确保在执行保护代码期间始终正确锁定和解锁互斥量。

在 main 函数中,用两个线程同时更新一个共享变量,通过 RAII 包装的 LockGuard 确保互斥量的正确使用。

标签:std,思想,RAII,互斥,mutex,LockGuard,资源
From: https://www.cnblogs.com/sfbslover/p/18407359

相关文章

  • 通过LinkedIn的思想领袖广告提升有机帖子效果,降低每次结果成本
    通过在LinkedIn上发布能够吸引互动(如点赞和评论)的自然帖子,并添加一个号召性用语(CTA)将其提升为思想领袖广告,Fame降低了每次结果的成本。目录摘要营销策略是什么?结果是什么?为什么这行得通?摘要营销策略是什么?在LinkedIn上,如果一个广告有许多互动,如点赞和评论,你将为你的投入获......
  • 极大似然估计的思想及计算[例题]
    0前言本文主要介绍极大似然估计的意义,并举出例题帮助读者理解。1思想极大似然估计(MaximumLikelihoodEstimation,MLE)是一种在统计学中估计模型参数的方法。它的基本思想是:找到一组参数值,使得在这组参数下,观测到的数据出现的概率(即似然函数)最大。假如有一个黑盒子,里......
  • 【多样化的思想】随机测试
    多样化通常是一件好事。为什么我们这么强调物种多样性,投入那么多人力物力财力去保护濒危的动植物?就是因为,只有保持物种的多样性,生态环境才能稳定和平衡。1956年,我国把麻雀列为四害之一,号召全民灭雀,保护粮食。全国各族人民热情高涨,积极响应,尤其是小朋友们,当时有一首诗是这么......
  • 模型 涌现思想
    系列文章分享 模型,了解更多......
  • 北大李戈团队提出:利用分片思想生成复杂函数的单测方法
    单元测试的目标是:通过对代码的最小单位进行独立测试,提高代码的可靠性,降低引入新错误的风险,确保代码功能的正确性,并提供一种持续验证的机制,帮助开发者保持代码的高质量和可维护性。环复杂度对待测函数的复杂度,有个指标:环复杂度,也称为圈复杂度或圈复杂度度量(CyclomaticComplexity......
  • 策略模式【Strategy Pattern】,什么是策略模式?核心思想?角色?优缺点?应用场景?略模式实现案
    目录设计模式专栏目录(点击进入…)策略模式【StrategyPattern】,什么是策略模式?核心思想?角色?优缺点?应用场景?略模式实现案例?目录什么是策略模式?策略模式核心思想策略模式的角色(1)策略接口(Strategy)(2)具体策略类(ConcreteStrategy)(3)上下文类(Context)策略模式的优缺点优点(1)......
  • 设计模式背后的设计原则和思想
    设计模式背后的设计原则和思想是一套指导我们如何设计高质量软件系统的准则和方法论。这些原则和思想不仅有助于提升软件的可维护性、可扩展性和可复用性,还能帮助开发团队更好地应对复杂多变的需求。以下是一些核心的设计原则和思想:1.设计原则设计模式背后的设计原则主要包......
  • 系统设计思想之Domain驱动
    一、DDD从放弃到入门   希望了解一套微服务框架的;希望学习到新技术的;开发的系统不复杂,模块少而独立的;当前自己设计的架构已满足拓展性,可复用性,技术与业务复杂度已分离的;   这几类人群不是DDD的目标人群,建议尽早放弃,学习领域驱动设计能得到的收获概括起来大致如下:  ......
  • 【C++】OOP面向对象思想
    面向对象编程(Object-OrientedProgramming,OOP)是一种编程范式,它将现实世界中的实体抽象为对象,通过对象之间的交互来设计软件系统。OOP的核心思想包括以下几个方面:封装(Encapsulation):封装是将数据(属性)和操作这些数据的方法(行为)捆绑在一起的过程。它隐藏了对象的内部状态和复......
  • Java中的一些思想
    Java中的一些思想目录Java中的一些思想1分类思想2分包思想3类与类之间的访问4static关键字4.1static修饰的特点4.2注意事项5信息管理系统5.1系统说明5.1.1学生管理系统5.1.2老师管理系统5.2实现步骤5.3代码实现5.3.1Student5.3.2Teacher1分类思想分工协作,专人......