string_view
operator+
vs. StrCat()
absl::Status
std::bind
absl::optional
and std::unique_ptr
absl::StrFormat()
make_unique
and private
Constructors.bool
explicit
= delete
)switch
Statements Responsibly= delete
AbslHashValue
and Youcontains()
std::optional
parametersif
and switch
statements with initializersinline
Variablesstd::unique_ptr
Must Be MovedAbslStringify()
vector.at()
auto
for Variable DeclarationsOriginally posted as TotW #18 on October 4, 2012
Updated 2022-11-16
Quicklink: abseil.io/tips/18
It happens all the time: you’re writing code and suddenly you need to assemble a
new string from a template and some run-time values. Maybe it’s an error message
from a failed Stubby call, maybe it’s the body of an email being sent from an
internal process. Probably the most common mechanism for string formatting
outside of google3 is sprintf/snprintf
. But as we wander through the codebase,
we see many things that people have done, and many places where C++ engineers
are spending too much of their time, too many cycles, and too many lines of code
to accomplish this task. In this week’s tip, we will walk through some common
options and point out their various drawbacks.
Some people still just reach for basic string concatenation:
std::string GetErrorMessage(const std::string& op, const std::string& user, int id) { return "Error in " + op + " for user " + user + "(" + std::to_string(id) + ")"; }
As we saw back in Tip #3, there are problems with this approach:
chains of calls to operator+()
wind up making (and wasting) temporaries, and
cause needless copies of your data.
Just like in Tip #3, absl::StrCat()
avoids those copies, handles the numeric
conversion for us (go/willitstrcat), and even allows us to operate on
string_view
efficiently (which is better in cases when we are called with a
C-style string):
std::string GetErrorMessage(absl::string_view op, absl::string_view user, int id) { return absl::StrCat("Error in ", op, " for user ", user, "(", id, ")"); }
However, it’s still a little difficult to see at a glance what the string actually will look like: Where are the spaces? Do the parentheses in the string match up properly?
However, an even better option exists: absl::Substitute()
. Substitute()
uses
the same techniques as StrCat()
to allow you to pass numeric values,
std::string
s, char*
s, and string_view
s. It doesn’t require you to remember
arcane format strings for numeric types (or string_view
).
Even though everyone can more-or-less understand printf-style format strings, Substitute format strings are just as hard to misinterpret:
std::string GetErrorMessage(absl::string_view op, absl::string_view user, int id) { return absl::Substitute("Error in $0 for user $1 ($2)", op, user, id); }
Good readability, and better performance? LGTM.