It does mean a thing

Some notes on software and beyond

Actions With RAII

You may know RAII as a cool idiom that makes it pretty easy to handle resources finalization automatically. When used properly, it reduces LoC, helps to avoid bugs and gives more safety for free. This makes RAII an important part of modern C++.

In recent talk on modern C++ Herb Sutter quoted Roger Orr on the importance of } in C++ (by the way, you probably would like to watch this talk if you read this blog). If you haven’t watched this talk you’d ask – what is that special in the closing bracket? This can be explained with the following example:

1
2
3
4
5
6
void function(Resource& resource)
{
  Lock lock(resource);

  // do things with locked resource safely
}

Things come easy here – the constructor of Lock locks the resource and the destructor of Lock unlocks it. The question is: when the resource is unlocked? It is guaranteed that once we get to the famous } – i.e. leave the scope of function – the lock object shall be destructed so the resource shall be unlocked. This is something called deterministic lifetime of objects, which makes it almost impossible to forget to free up the resource. Furthermore, we get even more safety for free. Say we did something wrong in our function. So wrong it raised an exception. Typical old approach (unlocking the resource once things are done explicitly) would definitely miss it and we leave the resource locked alone.

So what I wanted to tell you is that we can also take advantage of another unobvious scope – temporary return values:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <iostream>

struct Temporary
{
  ~Temporary()
  {
      std::cout << "Temporary destructed" << std::endl;
  }
};

Temporary temporary()
{
  return Temporary();
}

int main()
{
  temporary();
  std::cout << "Temporary should be already destructed" << std::endl;
}

An instance of Temporary will be destroyed immediately so this code should print the following text:

1
2
Temporary destructed
Temporary should be already destructed

This is an opportunity to do some experimental things. The simplest example is conditional actions (recently I pushed this to algorithme) which look like that:

1
2
3
4
5
6
int i = 0;
bool condition = true;
// doesn't call the lambda
algorithme::conditional_do([&] () { i++ }).when(false);
// does call the lambda
algorithme::conditional_do([&] () { i++ }).when(condition);

This is definitely a cumbersome replacement of the if statement but I still find it interesting. Other example of similar approach would be default (but customizable) behaviour:

1
2
3
4
5
// perform task by default (e.g. in blocking mode)
submit(task);

// perform task asynchronously
submit(task).async();

In this example the task is submitted not on call of submit but on destruction of some temporary object. This allows the user to ‘intercept’ the temporary before it is gone and change some behaviour. I can’t see this done without RAII-style temporaries. On the other hand, such code could go way too implicit to be good.

Comments