Sometimes Keeping The Type is Cheaper

Things have been quiet1 around here as of late. They’ll continue to be that way until CppCon as I’m preparing a talk and that’s keeping me too busy to do much posting at the moment2. If you’re going to be at CppCon and want to meet up feel free to use the email link over there on the right to get in touch. I always wonder who’s reading this stuff, and meeting one of them in person, while it would probably be weird, would also be cool.

While I am busy, apparently I’m not too busy for a someone is wrong on the internet post (that’s what you’re getting here). I came across this via the isocpp news feed. I like the idea a lot but have a small nit-pick with the implementation of the foreign constructor:

Font(std::function<void (Font)> visit) 
{
  visit(*this);
}           

I’ve fixed the constructor argument so that it has the required template parameters. And while I prefer my code to compile, the missing template parameters isn’t my issue. Instead, it’s the use of std::function in this context. std::function has to do type-erasure on the thing that is passed to it and the price for that is memory allocation and a virtual function call. The memory allocation might be avoided if your std::function implementation does small value optimization and said optimization is applicable to what you’re storing in the std::function. The virtual function will prevent inlining which we probably want to happen in this case.

To fix both of these issues we can define the Font constructor as

template <class visitor>
explicit Font(visitor&& visit) 
{
  visit(*this);
}           

This removes the use of std::function and along with it the memory allocation and virtual function call. Now one thing to worry about with templates is code bloat, you’re going to get one instance of the Font constructor for each visitor type that you call it with. In this case that shouldn’t be a problem as I would be really surprised if the constructor didn’t get inlined eliminating the bloat.

[Update: I changed the argument to Font to be a forwarding reference. This seems to be the emerging consensus on how to take arguments like this since we avoid copying the function object and can accept both const and non-const function objects.]

In this case std::function was the wrong tool to reach for. So when is it appropriate to use std::function? When you need to store the function for later. In that case we don’t want to worry about the actual type that was passed in, just that we can call it with the given argument types and get the appropriate type returned. That’s what std::function was designed for. In the case above, while we don’t care about visitor’s type, it is actually more expensive to abstract the type away so we may as well keep it around.


  1. Well…quieter than usual. 
  2. Like I need to be busy not to post. 
Advertisements

3 comments

  1. I believe you’d want that constructor to be ‘explicit’ to avoid making *any* type automagically convertable to ‘Font’ in your example.

    1. Yep, nice catch. I overlooked that.

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

%d bloggers like this: