如何使用RAII获取课堂资源?

7 c++ raii

有一个例子表明以这种方式使用RAII:

class File_ptr{
//...
   File* p;
   int* i; 
   public:
      File_ptr(const char* n, const char* s){
         i=new int[100];
         p=fopen(n,a); // imagine fopen might throws
      }
      ~File_ptr(){fclose(p);}
}

void use_file(const char* fn){
    File_ptr(fn,"r");
}
Run Code Online (Sandbox Code Playgroud)

是安全的.但我的问题是:如果抛出异常,p=fopen(n,a);那么分配给的内存i不会被返回.这是正确的假设,RAII然后告诉你每次你想要X安全,那么所有获得的资源X必须在堆栈上分配?如果X.a正在创建,那么资源a也必须放在堆栈上?再一次,我的意思是,如果有一些资源放在堆上,如何用RAII处理它?如果它不是我的类,即

Exc*_*ius 11

RAII的重点是不要将任何资源(如int-array)分配给悬空指针.相反,使用std::vector或指定数组指针std::unique_ptr.这样,资源将在异常发生时被销毁.

不,你不必使用STL,但是为了利用RAII,最低的基础资源(比如堆分配的数组)也必须使用RAII创建,最简单的方法是使用STL而不是而不是写自己的智能指针或向量.


CB *_*ley 1

将此视为您不想使用的智力练习std::vector,您需要将您的班级分开,以便他们承担单一职责。这是我的“整数数组”类。它的职责是管理整数数组的内存。

class IntArray {
public:
    IntArray() : ptr_(new int[100]) {}
    ~IntArray() { delete[] ptr_; }
    IntArray(const IntArray&) = delete; // making copyable == exercise for reader
    IntArray& operator=(const IntArray&) = delete;
    // TODO: accessor?
private:
    int* ptr_;
};
Run Code Online (Sandbox Code Playgroud)

这是我的文件处理类。它的职责是管理一个FILE*.

class FileHandle {
public:
    FileHandle(const char* name, const char* mode)
     : fp_(fopen(name, mode))
    {
        if (fp_ == 0)
            throw std::runtime_error("Failed to open file");
    }
    ~FileHandle() {
        fclose(fp_); // squelch errors
    }
    FileHandle(const FileHandle&) = delete;
    FileHandle& operator=(const FileHandle&) = delete;
    // TODO: accessor?
private:
    FILE* fp_;
};
Run Code Online (Sandbox Code Playgroud)

请注意,我将构造错误转换为异常;fp_作为一个有效的文件指针是我希望维护的一个不变量,因此如果我无法设置这个不变量,我将中止构造。

现在,使File_ptr异常安全变得很容易,并且该类不需要复杂的资源管理。

class File_ptr {
private:
    FileHandle p;
    IntArray i; 
public:
    File_ptr(const char* n, const char* s)
     : p(n, s)
     , i()
    {}
};
Run Code Online (Sandbox Code Playgroud)

请注意,缺少任何用户声明的析构函数、复制赋值运算符或复制构造函数。我可以交换成员的顺序,在任何一种情况下,哪个构造函数抛出并不重要。