2

I understand the concept of RAII: Use the destructor as a means to free resources, such as memory, or closing file handles/database connections. Coming from a Java background this was actually rather easy to understand because of the similarities to finally.

However, I do not quite understand when you actually should apply it. Obviously it should be implemented when initializing objects on the heap, but what are the other scenarios a normal programmer would have to use it for? Looking at this thread I found out that for example std::ifstream already has RAII implemented to handle the freeing of its file handle. So wrapping it in another object just to call ifstreamObj.close() in its destructor would be a waste of time. But I am pretty sure that this is not a general rule that applies to all of the libraries out there.

So my question is: when should I actually use RAII? Is there a general rule of thumb, a best-practice, or do I have to crawl through each and every class's documentation if I want to be sure? Or can I be certain that every class that implements a close()/free()/delete() (or something similar) method also takes care of calling it properly when necessary?

  • 2
    "So wrapping it in another object just to call ifstreamObj.close() in its destructor would be a waste of time" -- True. But if you were holding a reference to an ifstreamObj in a class that also does other things, wouldn't it be nice if that class used its RAII to free the ifstreamObj for you? And when that ifstreamObj was freed, wouldn't it be nice if that object took responsibility for cleaning itself up? – Robert Harvey Apr 21 '17 at 21:20
  • True. But I was rather concerned with what would happen if I declared the object on the stack and it going out of scope. Since the destructor of the stack variable is always called when it leaves the scope this is not an issue when RAII is being adhered to - but it can become a pretty big one if it's not. – KUSH42 Apr 21 '17 at 21:38
7

when should I actually use RAII?

When you acquire any resource in the member functions of your class and haven't delegated the responsibility to release those resources to another object/function, you need to make sure that you release those resources in the destructor.

If your class acquires a file handle by using std::ifstream::open(), you shouldn't have to explicitly call std::ifstream::close() since the destructor of std::ifstream will take care of it, i.e. the responsibility has been delegated to another object.

However, if your class acquires a file handle by using fopen(), you will have to make sure that destructor of your class calls fclose() appropriately.

Is there a general rule of thumb, a best-practice, or do I have to crawl through each and every class's documentation if I want to be sure?

As a rule of thump, you should assume that each class that you use, whether they are from the standard library, a vendor's library, or in-house library, adheres to the principle. If it doesn't, it's a defect and must be fixed by the party responsible for it.

You shouldn't have to call std::ifstream::close(). If the file doesn't get closed, you should inform the vendor that they need to fix the problem. In the mean time, you should write a wrapper class that takes care of the problem and use the wrapper class in rest of your code.

  • In c++, if you hold a member reference to an object like an ifstream that already has RAII semantics, are you responsible for freeing that object before you release your enclosing object, or does that object get freed automatically when its enclosing object gets released? – Robert Harvey Apr 21 '17 at 21:23
  • 1
    When you hold a reference to an ifstream, such as a std::ifstream& file;, then you are not responsible for freeing that object. The ifstream gets destructed whet it gets out of scope and its resources are released at that time. – R Sahu Apr 21 '17 at 21:24
  • 1
    @RobertHarvey What RHasu said is true if what's held by the class is a member value (i.e. if the member is contained by value in the class instance). In C++ a reference is more like a "pointer* than like a value, so if the member is a reference (not a value), then the instance you're referring to is somewhere else and it's lifetime is not synonymous with the lifetime of your class. – ChrisW Apr 21 '17 at 21:47
  • 4
    As a rule of thumb, I would assume a class does not use RAII unless the documentation for that class (one should always RTFM) says that the class does follow RAII. For example, std::mutex does not obey RAII, and the documentation says nothing about this fact. On the other hand, std::lock_guard and related class templates very explicitly say they do obey RAII. – David Hammen Apr 21 '17 at 21:49
  • 2
    @DavidHammen: I think you missed my point. The destructor of a mutex does correctly free the mutex's memory, and (for most reasonable implementations) the kernel object that the mutex uses for synchronization. So it does follow RAII, it just does so in a way that makes sense. mutex = "create and destroy a mutex". lock_guard = "grab and release a mutex that already exists." – Kevin Apr 22 '17 at 7:36
2

RAII is about automatic release of acquired resources in destructor - there is a run-time guarantee that destructor will be called before object instance is going away regardless of specific mechanism being used.

So it should be used always. At the same time when object is going away its members are going away too and each will have its destructor executed on the way out. So if these member objects are implemented correctly there is no need to do anything.

A very popular idiom is to create a holder object on the stack so resources will be freed when the scope is exited (including exception being thrown)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.