Questions tagged [raii]

Resource Acquisition Is Initialization (RAII) is a common idiom used in C++ to manage the lifetime of resources, including memory allocations, file handles or database connections. In brief, every resource should be wrapped in an owning class, whose lifetime controls the lifetime of the resource.

Wikipedia

Resource Acquisition Is Initialization (RAII) is a programming idiom used in several object-oriented languages, most prominently C++, where it originated, but also D, Ada, Vala, and Rust. The technique was developed for exception-safe resource management in C++ during 1984–89, primarily by Bjarne Stroustrup and Andrew Koenig, and the term itself was coined by Stroustrup.

Basic Example

The most basic example of RAII may look like this:

struct intarray {
  explicit intarray (size_t size) : array(new int[size]) {}
  ~intarray (){ delete[] array; }

  int& operator[](size_t idx) { return array[idx]; }
  const int& operator[] const (size_t idx) { return array[idx]; }

private:
  intarray (const intarray &);
  intarray & operator=(const intarray&);

  int* const array;
};

This class encapsulates a memory allocation (for an array of int), so that when the intarray class is created, it creates a resource (the memory allocation), and when it is destroyed, it destroys the resource.

A user of the class can now write code such as this to create an array whose size is determined at runtime:

void foo(size_t size) {
  intarray myarray(size);
  // no bounds checking in this example: assume that size is at least 15
  myarray[10] = 0;
  myarray[14] = 123;
}

This code will not leak memory. myarray is declared on the stack, so it is automatically destroyed when we leave the scope in which it was declared; when foo returns, myarray's destructor is called. And myarray's destructor internally calls delete[] on the internal array.

We can write a more subtle version of the function, which also will not leak memory:

void foo(size_t size) {
  intarray myarray(size);
  bar();
}

We know nothing about bar's behavior (although we assume that it will not leak memory), so it is possible that it may throw an exception. Because myarray is a local variable, it is still automatically destroyed, and so it will implicitly also release the memory allocation it was responsible for.

Without using RAII, we would have had to write something like this to ensure that no memory leaks could occur:

void foo(size_t size) {
  int* myarray = new int[size];
  try {
    bar();
    delete[] myarray;
  }
  catch (...){
    delete[] myarray;
    throw;
  }
}

By relying on RAII, we no longer have to write implicit cleanup code. We rely on the automatic lifetime of local variables to clean up their associated resources.

Note that in this simple example, the copy constructor and assignment operator were both declared private, giving us a class that can not be copied. If this had not been done, care would have to be taken in their implementation to ensure that the resource is only freed once. (A naive copy constructor would simply copy the array pointer from the source object, resulting in two objects holding a pointer to the same memory allocation, and so both will try to release it when their destructors are called).

Common solutions are either to use a reference counting scheme (so that the last object to be deleted will also be the one who finally deletes the shared resource), or simply cloning the resource when the RAII wrapper is copied.

RAII in the Standard Library

RAII is widely used in the C++ standard library. The container classes, such as std::vector employ RAII to control the lifetime of the objects they store, so that the user does not have to keep track of allocated memory. For example,

std::vector<std::string> vec;
std::string hello = "hello";
vec.push_back(hello);

contains numerous memory allocations:

  • the vector allocates an internal array, conceptually similarly to the intarray class described above,
  • a string is created, containing a dynamically allocated buffer storing the text "hello",
  • a second string is allocated in the vector's internal buffer, and this string also creates an internal buffer to store its data. The data from the first string is copied into the second string.

And yet, as library users, we did not have to call new even once, and nor do we need to call delete or worry about cleanup. We created our objects on the stack, where they are automatically destroyed when they go out of scope, and they take care of their memory allocations internally. Even when we copy from one string to another, the string implementation takes care of copying the internal buffers, so that each string owns a separate copy of the string "hello".

And when the vector goes out of scope, it takes care of destroying every object stored in it (which, in turn, is responsible for releasing its internal memory allocation), before releasing its internal buffer.

The standard library also employs RAII to manage other resources, such as file handles. When we create a file stream, it is a RAII wrapper class which takes ownership of the file handle used internally. So when the file stream is destroyed, the file handle is closed and destroyed as well, allowing us to write code like this:

void foo() {
    std::ofstream("file.txt") << "hello world";
}

Again, we create an object (in this case an output file stream), which internally allocates one or more resources (it acquires a file handle, and very likely also performs one or more memory allocations for internal buffers and helper objects), and as long as the object is in scope, we use it. Once it goes out of scope, it automatically cleans up every resource it acquired.

Smart pointers

Many people equate RAII with the use if common smart pointer classes, which is an oversimplification. As the previous two examples, RAII can be used in many cases without relying on a smart pointer class.

A smart pointer is an object with the same interface as a pointer (sometimes with minor restrictions), but which takes ownership of the object it points to, so that the smart pointer takes responsibility for deleting the object it points to.

The Boost library contains several widely used smart pointers:

  • boost::shared_ptr<T> implements reference counting, so that while many shared_ptr's may point to an object of type T, the last one to be destroyed is responsible for deleting the pointed-to object.
  • boost::scoped_ptr<T> has some similarity to the intarray example, in that it is a pointer that cannot be copied or assigned to. It is given ownership of an object at creation, and will, when it goes out of scope, destroy that object.

The C++ standard library contains a std::auto_ptr<T> (superseded in C++11 by std::unique_ptr<T>), which, like scoped_ptr allows only one pointer to own an object, but unlike it, also allows this ownership to be transferred, so that the original pointer loses ownership of the object, and the new pointer gains it. The original pointer then becomes a null pointer which does nothing when it is destroyed.

596 questions
0
votes
2 answers

Idiomatic move contructor for resource that can only be released once in destructor

In code which wrap a resource which should be freed once and only once, is it idiomatic to do something like the following to guarantee this? Is there a superior approach? class SocketWrapper { SocketWrapper() { fd = socket(AF_INET,…
0
votes
2 answers

Hide post-function calls in with statement

I have a function f that returns two parameters. After this function, I use the first parameter. I need the second one to glue things together with another function g. So my code would look like: a, b = f() # do stuff with a g(b) This is very…
hr0m
  • 2,643
  • 5
  • 28
  • 39
0
votes
2 answers

RAII char ** to be used as exec argument vector

I'm currently creating an app to launch external apps. The signature to launch the external apps is: int launchApp(int argc, char** argv); // argc = amount of arguments, argv = arguments To add arguments to a std::vector structure I use the…
A.Fagrell
  • 1,052
  • 8
  • 21
0
votes
1 answer

Guard in c++, destructor not called when the exception is not treated in main

If we consider the following code with g++ or clang, the destructor of the Guard class is not called when the exception is not catched at least in the main function. I made a thew googling, and did not find any usefull information. I use guard class…
Thomas
  • 95
  • 7
0
votes
3 answers

C++ RAII and polymorphism compatibility

There is no finally block in C++ because of RAII. Now if I have a pointer object and exception happens in one of the method, how this object will be deleted?. Here is a sample code I have written. class A { public: A() { cout<<"I am…
samnaction
  • 1,194
  • 1
  • 17
  • 45
0
votes
1 answer

Using shared pointers for run time array allocations

I have a C++ program where I need to allocate memory for a log (char*). I read about std::shared_ptr and how they will handle deletion of memory once scope is left. Will the code below automatically free the log buffer after the scope is…
user1291510
  • 265
  • 5
  • 14
0
votes
0 answers

C++ good practice: Let user pass a pointer or allocate the resource in the class itself

Sorry for the headline I wasn't sure how to correctly express my problem. I have a class that does generate an array based on a certain algorithm. The array length may vary so I'd like to allocate the array dynamically. The caller - of course -…
binaryguy
  • 1,167
  • 3
  • 12
  • 29
0
votes
2 answers

Owner object that takes pre-created values ? Wrong design?

It is a wrong design to have an object that is considered as the owner of it's components (or items in the case of an array / map) but that only deletes them and doesn't construct them ? For example if I have a hierarchy of classes : class A {…
Virus721
  • 8,061
  • 12
  • 67
  • 123
0
votes
1 answer

Understanding RAII object

I'm reading about RAII principle and have some questions about it. In fact, it encapsulates the resource. So, consider the class std::string. It has a constructor string (const char* s);. So, like smart pointers (e.g. template explicit shared_ptr…
stella
  • 2,546
  • 2
  • 18
  • 33
0
votes
0 answers

Language support of scope guard

Scope guard is very C++-way idiom. It good interacts with exceptions and compliant with RAII. C++ has no native support of scope guards. I mean clean syntax. At the moment I can only write a helper class: c-tor store the lambda as data-member and…
Tomilov Anatoliy
  • 15,657
  • 10
  • 64
  • 169
0
votes
1 answer

Resharper C++ and RAII - unused local variable

I have a code similar to this: std::unique_ptr get_raii_object() { return std::make_unique(/* Many parameters that I don't want to write several times, if I remove this function altogether */ ); } void some_code() { …
user972014
  • 3,296
  • 6
  • 49
  • 89
0
votes
3 answers

C++ Raii and stack unwinding

(I modified the original question to be more meaningful) With respect to return statement, are Raii object destroyed before/after/between return statement? for example size_t advance() { boost::lock_guard lock(mutex_); return…
Anycorn
  • 50,217
  • 42
  • 167
  • 261
0
votes
3 answers

Dangling pointer with explicit conversion

In Scott Meyrses Effective C++ he provided an exampple of bad usage of implicit conversions along with RAII classes: class Font { // RAII class public: explicit Font(FontHandle fh) // acquire resource; : f(fh) // use pass-by-value,…
St.Antario
  • 26,175
  • 41
  • 130
  • 318
0
votes
1 answer

RAII objects tr1:shared_ptr

I'm reading Scott Meyrses' C++ and come across the following code: class Lock { public: explicit Lock(Mutex *pm) // init shared_ptr with the Mutex : mutexPtr(pm, unlock) // to point to and the unlock func { lock(mutexPtr.get()); // see…
St.Antario
  • 26,175
  • 41
  • 130
  • 318
0
votes
3 answers

how to see the code added by the compiler?

How to see the added code in C++ by the compiler? E.g., we know that when an object of some class goes out of scope, the destructor for that object is called, but how do you see the specific code that does the destructor call? Is that code still…
Allanqunzi
  • 3,230
  • 1
  • 26
  • 58