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 #24 on Nov 26, 2012
by Titus Winters, ([email protected]) and Chandler Carruth ([email protected])
“To copy others is necessary, but to copy oneself is pathetic.” - Pablo Picasso
Note: see also TotW #55 and TotW #77 for guidance on name counting and copies vs. moves.
When evaluating whether copies get made within any given scope (including cases triggering RVO), check how many names your data refers to.
You will have two copies of the data at any point where you have two live names for those copies. To a good first approximation, the compiler will (and often must) elide copies in all other cases.
Between the move semantics of STL containers (introduced automatically with the switch to C++11) and copy constructor elision by the compiler, we are rapidly converging on this rule providing not merely a lower bound on the number of copies, but a guarantee. If your benchmarks show that more copies are being made, it is likely a compiler bug; your compiler probably needs a fix.
So if your code is structured such that there are two names for the data at some point during the execution, you should expect a copy. If you avoid introducing a name which could possibly refer to the data, you’ll help ensure the compiler can remove the copy.
Let’s look at some examples of how this works in practice:
std::string build();
std::string foo(std::string arg) {
return arg; // no copying here, only one name for the data “arg”.
}
void bar() {
std::string local = build(); // only 1 instance -- only 1 name
// no copying, a reference won’t incur a copy
std::string& local_ref = local;
// one copy operation, there are now two named collections of data.
std::string second = foo(local);
}
Most of the time, none of this matters. It is far more important to ensure that your code is readable and consistent, rather than worrying about copies and performance. As always: profile before you optimize. But, if you find yourself writing code from scratch – and can provide a clean and consistent API that returns its values – don’t discount code that seems like it would make copies: everything you learned about copies in C++ a decade ago is wrong.