Value-initialization with Boost

One of the fundamental concepts in STL is RegularType. This is more-less what containers expect of their elements:

  • default construction,
  • destruction,
  • copy-ability (copy constructor and copy assignment),
  • movability (move constructor and move assignment),
  • equality (operator==),
  • ordering (operator<).

C++ does a lot to help make POD types regular. We only write:

struct Point {
    double x;
    double y;
};

And we get destructor, copy operations and move operations for free. There are still some things to be wished. We do not get operator== although compiler could easily generate one for us: two PODs are equal if all their members are equal. Compiler could also generate a default operator<. You might argue that there is no natural less-than relation for points, but in the context of STL we only require an operation that enables storing PODs in associative containers: in such cases a simple lexicographical comparison will do. What about default constructor? Technically we do get it, but the value of such point is indeterminate. We would rather want to have a deterministic natural value (0, 0). While we have to live with the former two ‘deficiencies’, we can mitigate the latter one with Boost’s tool value_initialized. This is what this post is about.

boost::value_initialized<T>

The documentation for boost::value_initialized<T> says that its purpose is to allow uniform value initialization in generic components and provide workarounds that enable correct value initialization on deficient compilers. The usage we are describing in this post is different, we want to automatically generate a default constructor for a normal (non-generic) type. With the Boost tool we can declare our point type like this:

struct Point {
    boost::value_initialized<double> x;
    boost::value_initialized<double> y;
};

Now, x and y are almost doubles, but they are value-initialized (in this case, initialized to value 0) by default. Now our default-initialized points will always have value (0, 0), and we need not define our default constructor explicitly.

And we could end at this point; but if you really found this technique interesting or useful and intend to try it out, there are a number of problems you will encounter. The remainder of the post lists these problems.

First, boost::value_initialized<T> is a different type than T. The former defines conversion operators to type T& and T const&, so in many contents the wrapper is indistinguishable from T:

void increment( double & d ) {
    d += 1.;
}

Point p;
increment( p.x ); // ok
double x1 = p.x;  // ok

However other, seemingly innocent, operations fail to compile:

Point p;
p.x = 1.; // error

There is already a bug report for that missing assignment operator issue in Boost. But in current Boost version (1.47.0), the operator is still missing. In order to work around this problem, you can use an explicit conversion:

Point p;
get(p.x) = 1.;  // ok
get(p.x) += 1.; // ok

This makes the syntax uglier but works in all arbitrarily complex situations.

Debugger visualizer

Another problem emerges when you try to debug the code that uses objects of type value_initialized<T>. If you look inside the object in the debugger, the value of T is nowhere to be found. The wrapper uses raw memory storage in the implementation, and only casts it to T& when necessary. In order to make value_initialized<T> display as nicely as T in your debugger, you need to teach your debugger how it should display instantiations of template value_initialized. I only know how to do it in my IDE — Visual Studio 8. Boost offers a number of Visual Studio 8 debugger visualizers for a number of its libraries. There is no visualizer for value_initialized though. Luckily, Boost also provides instructions on how to write and install visualizers for your own types. With this help we can write our visualizer for value_initialized. Here is the code for Boost 1.42:

boost::value_initialized<*>{
    preview
    (
        *(($T1 *)(&$e.x))
    )
}

For Boost 1.47, the code would be:

boost::initialized<*>{
	preview
	(
		*(($T1 *)(&$e.x))
	)
}

boost::value_initialized<*>{
	preview
	(
		*(($T1 *)(&$e.m_data.x))
	)
}

If you want to know what that code means and how it can be installed in your Visual Studio (8 or higher) environment you will need to refer to the above-mentioned instructions. I guess you could enable a similar pretty printing in GDB…

Advertisements
This entry was posted in programming and tagged , , . Bookmark the permalink.

One Response to Value-initialization with Boost

  1. Michal Mocny says:

    In C++11 you can also use default member initialization values.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s