How to use RAII to acquire class resources?

There is an example that shows that using RAII in this way:

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"); } 

is safe. but my question is: what if in p=fopen(n,a); there is an exception, the memory allocated for i is not returned. Is it possible to assume that RAII tells you that every time you want X be safe, all resources received by X should be allocated on the stack? And if Xa is being created, then should resources a also be pushed onto the stack? and again, and again, I mean, finally, if there is some resource located on the heap, how can it be processed using RAII? If this is not my class ie

+7
source share
6 answers

Considering this as an intellectual exercise in which you do not want to use std::vector , you need to separate your classes so that they have one responsibility. Here is my class "integer array". Its task is to manage memory for an integer array.

 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_; }; 

Here is my file handling class. His responsibility is to manage 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_; }; 

Note that I am converting my build error to an exception; fp_ , which is a valid file pointer, is an invariant that I want to support, so I abort the construction if I cannot set this invariant.

Now making File_ptr exception File_ptr easy, and the class does not require complex resource management.

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

Note the absence of any user-declared destructor, copy assignment operator, or copy constructor. I can change the order of the members, and in any case, it doesn't matter which constructor throws.

+1
source

The whole point of RAII is NOT to assign any resources (like int -array) to dangling pointers. Instead, use std::vector or assign the array pointer something like std::unique_ptr . Thus, resources will be destroyed as exceptions arise.

And no, you do not need to use STL, but to use RAII, the lowest basic resources (for example, arrays allocated in heaps) must be created using RAII, and the easiest way to do this is to use STL instead of writing your own smart pointer or vector.

+11
source

If the exception occurs after new , you need to catch the exception and delete the pointer in the constructor, and then click again in this case, the destructor will not be called, since the object is never built.

otherwise, if i is std :: vector, it will automatically clear

+3
source

One way to handle this is to put everything that can be invalidated with an exception into a local variable that itself uses RAII, and then assign it to its members at the end when it is safe.

 class File_ptr{ //... File* p; int* i; public: File_ptr(const char* n, const char* s) i(NULL), p(NULL) { unique_ptr<int> temp_i=new int[100]; // might throw std::bad_alloc p=fopen(n,a); // imagine fopen might throws // possibility of throwing an exception is over, safe to set members now i = temp_i.release(); } ~File_ptr(){fclose(p);} } 

See Exclusion Security for more information.

+3
source

If you know what this throws, put it in a try-catch .

 File_ptr(const char* n, const char* s) { i=new int[100]; try { p=fopen(n,a); // imagine fopen might throws } catch(...) { delete[] i; throw; } } 
+2
source
 File_ptr(const char* n, const char* s) { std::unique_ptr<int[]> sp(new int[100]); p = fopen(n, s); i = sp.release(); } 
+1
source

All Articles