intermediate

The Variant Saga: A happy ending?

Variant is like a union, only it tells you what it currently contains, and it will barf if you try to get something out of it that is does not currently contain. It's the type safe sibling of the union:

variant<double, string> v = 42.;
double d = get<double>(v);

I had proposed a variant many moons ago (N4218). After many discussions it seemed that the committee cannot agree on what the ideal C++ variant would look like. I will resolve this cliffhanger -- but before doing that let me introduce you to some of the key discussion points.

An ideal variant will always contain one of its alternative types. But look at this code snippet:

variant<string, MyClass> v = "ABC";
v = MyClass();

The second line will destroy the old value contained in the variant and construct the new value of a different type. Now suppose that the MyClass construction threw: what will the variant contain? What happens when you call get<1>(v)? What happens when the variant gets destroyed?

We either provide the strong exception guarantee (the variant would still contain the string) -- but this requires double buffering, as for instance boost::variant does. Or we could restrict the alternative types to only those that are nothrow_move_constructible. Or we make this a new state -- "invalid, because the variant has been derailed due to an exception thrown during type changing assignment". Or we say "you shouldn't write code that behaves like this; if you do you're on your own", i.e. undefined behavior. The committee was discussing what to do, and so was The Internet. There are other design decisions -- default construction, visitation etc -- but they are all insignificant compared to how to deal with the throwing, type-changing assignment.

I have tried to present the options and their pros and cons in P0086. In short: it's incredibly difficult and fragile to predict whether a type is_nothrow_move_constructible. And double buffering -- required for a strong exception guarantee -- kills the quest for an efficient variant. But efficiency is one of the main motivations for using a discriminated union.

After the second Library Evolution Working Group (LEWG) review in Lenexa, we got P0088R0: a design that was making this invalid state extremely rare. But if it happened, access to the value would result in undefined behavior. This caused a vivid reaction from the committee members. And from The Internet. Hundreds of emails on the committee email lists. Many many smart and convincing blog posts.

In the end, different parts of the committee strongly supported different designs -- and vetoing other designs. Massive disagreement. So when we came to our C++ Standards Meeting in Kona, it was immediately clear that we needed to expose this to the full committee (and not just LEWG). The expectation was that we would declare variant dead, and keep it locked away for the next five years. At least. (An I would have time to water my fishes again.)

So back to the cliffhanger. On the full committee, Monday evening stage in Kona were David Sankel and I. We presented (and represented) the different design options. While we were discussing with the committee members, live and uncut and on stage, David and I realized that we could make it happen. "The Kona Kompromise": similar to P0088R0, but instead of undefined behavior when extracting the value of such a zombie variant it would just throw!

The Kona Kompromise means that we don't pay any efficiency for the extremely rare case of a throwing move. The interface stays nice and clean. A variant of n alternatives is a "mostly" an n-state type. It offers the basic exception guarantee at no relevant performance loss. It is a safe vocabulary type for every-day use, also for novices. The vast majority of the committee was convinced by this idea. Almost everyone in the room was happy!

Do we have a std::variant now? Not yet. But we are a giant leap closer: variant is now under wording review with the Library Working Group (LWG); I will publish a new revision in the Kona post-mailing (P0088R1). This will get re-reviewed in Jacksonville, first week of March. Once LWG gives the green light, the full committee can vote variant into a Technical Specification (TS) as std::experimental::variant. Now that a large fraction of the committee has expressed its consent (happiness, even!), I expect that this will be in the TS called Library Fundamentals, v3. It might or might not make it into C++17 -- that depends mostly on how quickly I manage to bring P0088 into an acceptable state, and how quickly we will gain use experience with variant.

So there is one thing I'd really appreciate your help with: std::experimental::variant will show up in library implementations near you, likely in their first releases next year. It would be fantastic if you could try it out, and as importantly: give feedback, on the public forums or by contacting me directly ([email protected]). Your feedback will tell us whether the design decisions we took are the right ones, for instance regarding default construction, visitation, performance, and especially converting construction and assignment. As they say here: Mahalo!

Axel Naumann, CERN ([email protected])

 

6 topics on starting and running a User Group

I posted an update on my founding C++ User Groups article from 2 years ago:

6 topics on starting and running a User Group

by Jens Weller

From the article:

Almost two years ago I blogged about founding C++ User Groups, since then I have learned a lot more on the topic, and I want to share that experience with you in this blog post. While my focus here at Meeting C++ is C++, this post is more on the topic of a User Group, so its also useful to you, if you want to start a user group on something else. Yet, I might strive away into C++ lands in this post...

Becoming a Rule of Zero Hero--Glennan Carnie

Everything is in the title:

Becoming a Rule of Zero Hero

by Glennan Carnie

From the article:

Previously, we’ve looked at The Rule of Zero which, in essence, says: avoid doing your own resource management; use a pre-defined resource-managing type instead.

This is an excellent guideline and can significantly improve the quality of your application code. However, there are some circumstances where you might not get exactly what you were expecting. It’s not that the code will fail; it just might not be as efficient as you thought.

Luckily, the solution is easy to implement and has the additional side-effect of making your code even more explicit.

New updates of CppHints.com, service of recommendations on C++ programming from PVS-Studio team

New updates of C++Hints, service of recommendations on C++ programming

Changes in CppHints.com

by PVS-Studio Team

We got a lot of positive feedback from our readers and continue developing the C++Hints project. We have also answered two requests, that we saw quite often in the letters:

By this moment we have published the following articles:

Using Variadic Templates cleanly--Florian Weber

Variadics are even more easy to use than we tought:

Using Variadic Templates cleanly

by Florian Weber

From the article:

When one comes across examples for variadic templates, almost always recursion is used to achieve almost everything, for example like this:

// We are lucky: the author correctly used zero
// arguments instead of one as the base-case,
// thereby avoiding code-duplication:
inline void print_to_stream(std::ostream&) {}

template<typename Head, typename...Tail>
void print_to_stream(std::ostream& stream, const Head& h, const Tail&... t) {
  stream << h;
  print_to_stream(stream, t...);
}

In this article we will see what better alternatives for this rather clumsy hack exist and see how we can write a better version with less code...

More than you need--Andrzej Krzemieński

Some thoughts about what the standard provides by default:

More than you need

by Andrzej Krzemieński

From the article:

The classes you design can do more (in terms of allowed operations) than what you could figure out from just looking at their member function declarations. The C++ Standard defines a number of cases where certain expressions involving your type are valid, even though there are no corresponding member function declarations. Sometimes this is just what you need; but sometimes the additional operations you never asked for can have grave negative impact on your program correctness...

 

Quick Q: What container should I use to reduce fragmentation caused by lots of small allocations?

Quick A: The only one matching the requirements is a std::deque, but it might be worth to consider using a memory pool.

Recently on SO:

What C++ std container should I use to reduce fragmentation caused by lots of small allocations?

Since you're asking specifically for a standard container, std::deque is the most promising option given your requirements. As long as you only add elements, the existing ones are not relocated, and references/pointers (but not iterators) remain valid. When removing elements, you may however need to leave gaps or swap the element to remove with the last element.

std::vector is not stable, and std::list, std::forward_list as well as all the associative containers are fragmented.

Looking at Boost.Container, you have additional options, however with other trade-offs:

boost::flat_map provides contiguous storage (like std::vector), but with it the stability problem
boost::stable_vector offers element stability at the cost of contiguity.
Alternatively, you can have a look at pool allocators (like Boost.Pool). They provide low fragmentation and fast allocation, and the container in front of it can still be used like a normal container.

CppCon 2014 Unicode in C++--James McNellis

Have you registered for CppCon 2015 in September? Don’t delay – Registration is open now.

While we wait for this year’s event, we’re featuring videos of some of the 100+ talks from CppCon 2014 for you to enjoy. Here is today’s feature:

Unicode in C++

by James McNellis

(watch on YouTube) (watch on Channel 9)

Summary of the talk:

In some programming languages, text processing is easy. Unfortunately, C++ is not one of those languages. C++ lacks good, built-in support for Unicode, though the situation is starting to improve.

This session will begin with a brief overview of text encodings, and an introduction to Unicode and the various Unicode encodings. We'll look at the woeful state of Unicode support in C++98 (or, really, lack thereof), then take a look at the improvements that were made in C++11 and other improvements that have recently been proposed for standardization. We'll finish up with a discussion of several libraries designed to make it easier to work with Unicode in C++, including the widely-used, open-source International Components for Unicode (ICU) library.