C++ and passing by value

I was recently responding to some code review feedback and it occurred to me I could write it up for this blog. Which also means I start 2021 with a blog post, not something I’ve done in ages.

The question was around why I passed an non-trivial object by value to a function. The recipient function was going to copy the object, and the short version is “clang tidy complains if you don’t pass by value and move”.

For the longer version, consider this super simple example:

#include <string>

struct Thing {
  std:string s_;
  void set_s(std::string s) { s_ = std::move(s); }

Now consider what happens when we do something like set_s("moo");:

Short version: exactly one “real” string construction is done, and then there’s a bit of pointer movement, but nothing more expensive.

If, however, we change the parameter to a const string & in set_s, and remove the move in set_s():

This means we do the allocation twice, copy the string data twice, and do a deallocation once. This is more expensive!

You can see in Compiler Explorer that the string::_M_create method is called twice in the second case, whereas for this small string it’s all inlined in the first case.

  1. In this case, with a short string like "moo" no real allocations are done in this case. There’s an thing called the “small string optimization” (SSO) kicking in; the string object holds small strings by value inside itself directly. If you change the string to something longer you see more work – see here

Filed under: Coding
Posted at 17:35:00 GMT on 2nd January 2021.

About Matt Godbolt

Matt Godbolt is a C++ developer working in Chicago for Aquatic. Follow him on Mastodon.