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.

Leave a Reply

Your email address will not be published. Required fields are marked *