Configuration file version management with boost::serialization and boost::archive

One of the simplest ways to handle your configuration in a C++ program is to put it in a serializable structure – something that looks a bit like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
#ifndef configuration_h
#define configuration_h
 
#include <boost/filesystem/path.hpp>
#include <boost/serialization/access.hpp>
 
namespace MyApp
{
	struct Configuration
	{
		enum SomethingImportant {
			first_possibility__,
			second_possibility__,
		};
 
		Configuration()
			: is_default_(true)
			, something_important_(first_possibility____)
			, something_added_later_(0)
			, something_added_even_later_(0)
		{ /* no-op */ }
 
		template < typename Archive >
		void save(Archive & ar, const unsigned int version) const
		{
			ar	& something_important_
				& something_added_later_
				& something_added_even_later_
				;
		}
		template < typename Archive >
		void load(Archive & ar, const unsigned int version)
		{
			ar	& something_important_
				;
			if (version > 0)
			{
				ar	& something_added_later_
					;
			}
			else
			{ /* use default */ }
			if (version > 1)
			{
				ar	& something_added_even_later_
					;
			}
			else
			{ /* use default */ }
			is_default_ = version < 2;
		}
		BOOST_SERIALIZATION_SPLIT_MEMBER()
 
		SomethingImportant something_important_;
		int something_added_later_;
		int something_added_even_later_;
		bool is_default_;
	};
}
BOOST_CLASS_VERSION(MyApp::Configuration, 2);
 
#endif

One of the nice things about boost::serialization and its sibling, boost::archive, is that you can version your classes using it. In the example above, the class is at its third iteration and, at each iteration, a member has been added. In the save method, this only implied adding a single line of code each time – lines 27 and 28, resp. In the load method, this implied a wee bit more: this is where we need to check the version of the class being loaded (lines 36 and 42 of the example) and act accordingly.

In order for the application to know that at least some of the loaded structure contains default values, set by the constructor (16 through 21), I’ve added a boolean member to the class (line 57) which is set to true by the constructor (line 17) and to false by load, but only if the loaded class’ version is greater than or equal to the version that last added a member to be serialized.

When removing a member from the saved structure, if you don’t want boost::archive to throw an exception during loading, you still have to read it. This makes it a bit more difficult to handle removing members than to handle adding members. The reason for this is that older versions of your application will have saved the information and, without a clear definition of that information and, therefore, code that reads it, the implementation will not know to skip over the saved information. The alternative, as I do in one application I use, is to simply abort loading altogether and ask the user to re-enter the configuration. The reason I did this in this case was that there were very few cases in which the application would be upgraded from the previous version to the new one, without requiring re-configuration and re-validation anyway, so I could afford to impose re-configuration and (thus) not keeping the older definition of the saved information around just to read the configuration and throw it away at run-time. Which option is best for you (keeping the code around to read the data or forcing the user to re-configure) depends on your circumstances.

About rlc

Software Analyst in embedded systems and C++, C and VHDL developer, I specialize in security, communications protocols and time synchronization, and am interested in concurrency, generic meta-programming and functional programming and their practical applications. I take a pragmatic approach to project management, focusing on the management of risk and scope. I have over two decades of experience as a software professional and a background in science.
This entry was posted in C & C++. Bookmark the permalink.