C++ 资源获取是指初始化(RAII)?

C++ 资源获取是指初始化(RAII)?,c++,raii,C++,Raii,资源获取的意思是初始化(RAII)?这是一个编程习惯用法,简单地说就是 将资源封装到类中(其构造函数通常(但不一定**)获取资源,其析构函数总是释放资源) 通过类的本地实例使用资源* 当对象超出范围时,资源将自动释放 这保证了无论资源在使用中发生什么,它最终都会被释放(无论是由于正常返回、包含对象的破坏还是引发异常) 是C++中广泛使用的一种好方法,因为除了处理资源的安全方法之外,它还使代码更干净,因为不需要将错误处理代码与主要功能混合。 *更新:“局部”可能指局部变量,或类的非静态成员变量

资源获取的意思是初始化(RAII)?

这是一个编程习惯用法,简单地说就是

  • 将资源封装到类中(其构造函数通常(但不一定**)获取资源,其析构函数总是释放资源)
  • 通过类的本地实例使用资源*
  • 当对象超出范围时,资源将自动释放
这保证了无论资源在使用中发生什么,它最终都会被释放(无论是由于正常返回、包含对象的破坏还是引发异常)

是C++中广泛使用的一种好方法,因为除了处理资源的安全方法之外,它还使代码更干净,因为不需要将错误处理代码与主要功能混合。

*
更新:“局部”可能指局部变量,或类的非静态成员变量。在后一种情况下,成员变量用其所有者对象初始化和销毁

**
更新2:正如@sbi所指出的,虽然资源通常在构造函数内部分配,但也可以在构造函数外部分配并作为参数传入。

“RAII”代表“资源获取是初始化”,实际上用词不当,因为它不是资源获取(以及对象的初始化)它与之相关,但释放资源(通过销毁对象的方式)。
但RAII是我们得到的名字,而且它一直存在

该习惯用法的核心特点是将资源(内存块、打开的文件、解锁的互斥锁,你可以说)封装在本地自动对象中,并让该对象的析构函数在对象所属范围结束时释放资源:

{
  raii obj(acquire_resource());
  // ...
} // obj's dtor will call release_resource()
当然,对象并不总是本地的、自动的对象。它们也可以是类的成员:

class something {
private:
  raii obj_;  // will live and die with instances of the class
  // ... 
};
如果这些对象管理内存,它们通常被称为“智能指针”

这有很多变化。例如,在第一个代码片段中,如果有人想要拷贝<代码> Obj>代码>,会发生什么。最简单的方法是简单地不允许复制。<代码> STD::UnQuyJPPT<代码>,作为下一个C++标准的标准库的一部分,智能指针是这样做的。> 另一个这样的智能指针,

std::shared_ptr
具有资源的“共享所有权”(一个动态分配的对象)它有效。也就是说,它可以自由复制,并且所有副本都指向同一对象。智能指针跟踪有多少副本指向同一对象,并在销毁最后一个副本时将其删除。
第三种变体的特点是
std::auto_ptr
,它实现了一种移动语义:对象仅由一个指针拥有,尝试复制对象将导致(通过语法黑客)将对象的所有权转移到复制操作的目标。

本书将RAII描述为:

  • 获取所有资源
  • 利用资源
  • 释放资源
  • 在哪里

    • 资源被实现为类,所有指针周围都有类包装器(使它们成为智能指针)

    • 资源通过调用其构造函数获得,并通过调用其析构函数隐式释放(与获取顺序相反)


    这是一个非常强大的概念,它是一个难以置信的强大概念,也许是C++开发者在切换到其他语言时错过的1件事情之一。有一种尝试将这个概念重命名为<强>范围绑定的资源管理< /St>,尽管它似乎还没有被抓到。 当我们说“资源”时,我们不仅仅是指内存——它可以是文件句柄、网络套接字、数据库句柄、GDI对象……简言之,我们有有限的资源,因此我们需要能够控制它们的使用。“范围绑定”方面指的是对象的生存期绑定到变量的范围,因此当变量le超出范围,则析构函数将释放资源。这一特性的一个非常有用的特性是,它有助于提高异常安全性。例如,比较如下:

    RawResourceHandle* handle=createNewResource();
    handle->performInvalidOperation();  // Oops, throws exception
    ...
    deleteResource(handle); // oh dear, never gets called so the resource leaks
    
    和RAII一个

    class ManagedResourceHandle {
    public:
       ManagedResourceHandle(RawResourceHandle* rawHandle_) : rawHandle(rawHandle_) {};
       ~ManagedResourceHandle() {delete rawHandle; }
       ... // omitted operator*, etc
    private:
       RawResourceHandle* rawHandle;
    };
    
    ManagedResourceHandle handle(createNewResource());
    handle->performInvalidOperation();
    

    在后一种情况下,当抛出异常并释放堆栈时,本地变量将被销毁,从而确保我们的资源得到清理并且不会泄漏。

    自编译器发明以来,程序员一直在想方设法避免手动内存管理的噩梦。使用垃圾列的编程语言选择器使生活更轻松,但却以性能为代价。在这篇文章中,Toptal工程师Peter Goodspeed Niklaus向我们介绍了垃圾收集器的历史,并解释了所有权和借用的概念如何帮助消除垃圾收集器而不损及它们的安全保证。

    RAII c有三个部分姑娘:

  • 资源在析构函数中被放弃
  • 类的实例是堆栈分配的
  • 在构造函数中获取资源。此部分为 可选,但常见
  • RAII代表“资源获取即初始化”。RAII的“资源获取”部分是您开始必须在以后结束的事情的地方,例如:

  • 打开文件
  • 分配一些内存
  • 获取锁
  • “is初始化”部分意味着获取发生在类的构造函数内部


    < P>对象的生命周期是由它的范围决定的。然而,有时我们需要或有用的是创建一个独立于它所创建的范围的对象。在C++中,操作符<强> >代码>新< /Calue> <强>被用来创建SUC。
    void fn(const std::string& str)
    {
        std::vector<char> vec;
        for (auto c : str)
            vec.push_back(c);
        // do something
    }