Search code examples
c++raii

Should I apply RAII to all arrays I allocated?


I'm studying C++ now. It is a so complicated language that I'm not sure which feature I should use and when to use.

C++ Primer introduces RAII as a method to ensure exception safety. Does that mean, as a good behavior, when I want to use an array, I should put array into an class to allocate and destroy resources. I know my idea is very simple, or naive.

I'm just curious about what is good C++ coding behavior.


Solution

  • RAII is a recommended idiom for resource management -- resources can be threads, memory... I frequently encounter long-time developers who don't understand RAII or how to use it, so there's no shame in asking. Unfortunately, I think you need a little background and terminology to understand it. In C++ you can create objects in one of two kinds of memory: The stack and the heap.

    The Stack: Consider this code:

    class Foo
    {
        // some implementation
    }
    
    void bar()
    {
      Foo f;
      // do something with f.
      // maybe it throws an exception, maybe not.
    }
    

    Here the object f of type Foo has been created on the stack. When the running program leaves the scope in which f was created (in our example when it leaves the function bar()), f's destructor will called, regardless of how it leaves the scope. It might leave scope because the function executed successfully, or it might leave scope because an exception was thrown.

    Heap allocation Now consider the following:

    class Foo
    {
    // same thing
    }
    
    void bar()
    {
    Foo* f = new f;
    // whatever
    delete f;
    }
    

    In this case we created the object f on the heap. You can tell we did so because we called the new operator. Whenever an object is created with new, we have to call delete in order to free the memory up. This can be error prone, because people forget to call delete, or they return the pointer and it's unclear where the pointer should get deleted, or because an exception is thrown. RAII is a solution to all those, and it should be your first tool of choice.

    But that doesn't mean you should put your arrays in a class (well it kind of does in some circumstances, but probably not in the way that you mean). Consider the following:

    void foo()
    {
         // c-style array, but fixed size.
         int bar_stack[5];
    
         // c-style array, dynamically allocated!
         unsigned int array_size = get_array_size();
         int* bar_heap = new int[array_size]
    
         // c++ way:
         std::vector bar_vector(array_size);
     }
    

    In the first example we have a fixed c-style array, it's allocated on the stack, so it's nothing to worry about. In the second case, it's dynamically allocated (the compiler doesn't know the size, its available at run time), so we would need a delete, meaning we'd need to protect against exceptions and make sure there's a clear owner. In the third case we just use a vector, which is a standard container.

    Now I provided all that because I was afraid you wouldn't understand the short answer which is: Yes you should generally use RAII to manage your resources, but you should use std containers, not arrays. Why? Because std containers provide RAII for you -- unless you make a container of pointers, or allocate your vector on the heap.

    I hope that helps.