When RAII fails you

I’ve already mentioned RAII briefly in this post. But as a recap, RAII is a wonderful concept which allows you to stop worrying about the cleanup. Whether that’s freeing memory, file handlers, of general cleanup.

There are however some cases where RAII won’t work as advertised. In such cases, you don’t pass go, you don’t collect your 200$, and you don’t get the cleanup RAII is meant to do.

The premise of RAII is that as variable goes out of scope, the variable is automatically deleted. This is where we can implemented a custom destructor to handle the cleanup we want. However, for that to happen, the destrucor must be called.

Let’s say we have this piece of code which: Copies a file over to a test area. Runs some tests using the test data in the file. Then once the RAII variable goes out of scope for any reason (exception, normal execution) the file is deleted.

{
	FileCopierRAII fileCopier{ “testFilename” };

	// Modify the file for our test.
	...
	// Run unit tests  
	...
	// Validate results. Call std::abort
 	// if any issues detected. 
	assert( /*Check results*/ );
	
} 
// Temp test file copied over is cleaned
// up automatically here as variable goes
// out of scope.

This looks fairly reasonable at first glance. However the issue lies in what happens within the call to assert. If the assert is true, the cleanup happens, however if the statment passed to assert evaluates to false, then there is no cleanup. How can that be?

When assert fails, it calls std::abort. According to the standard [Termination, paragraph 7]:

Calling the function std::abort() declared in <cstdlib> terminates the program without executing any destructors and without calling the functions passed to std::atexit() or std::at_quick_exit().

The key here is that std::abort does not call the destructors. For a lot cases that may be good enough, however for our case with files being copied over, that’s clearly not the case as the file will not be cleaned up and will linger post termination.

Conclusion: When you you can cases where std::abort or asserts in your code, it’s necessary to handle any cleanup by yourself, without depending on RAII.

Modern C++ and backwards compatibility for keyword auto

With the introduction of keyword auto to implement type deduction, ever wonder why this “new” keyword didn’t break tons of old code when projects were migrated to newer compilers? Turns out keyword auto has been reserved for quite some time in the standard. Therefore it isn’t a new keyword at all, but one which was rarely used. The standard addresses this in the appendix sections and . These sections state that auto can no longer be used as a storage class specifier. The rationale given for this change, is basically that the keyword is being re-purposed for better use.

What was the original use of auto? It was to be used to define automatic storage duration of local variable within a block. The block could be a function or just a block of code. This means the local variables are created in the block, and cease to exist at the end of the block. For example:

 // Example 1
{
   // Automatic storage duration by default.
   int myVar = 0;
   …
   // Not valid code starting with C++11.
   auto int otherVar = 0; 

} // Both vars cease to exist.

Or, more interestingly:

// Example 2
std::mutex myMutex;
{
   // Automatic storage duration. 
   std::lock_guard<std::mutex> myLockGuard(myMutex);
   ...
   
} // variable  ceases to exist and  mutex is released.

As shown in the example 2 above, this automatic storage duration is a key part of RAII . The other types of storage being register, static, extern, thread_local. The fact that auto storage class is the default, doesn’t make it particularly useful. Therefore, it’s easy to see why having a name like “auto” it was recycled to it’s new purpose.