Proposed idiom for efficient use of move semantics
If you just want the proposal, skip to "consider the following
definition of fill() instead".
In this post I'll use "string" to represent any class for which
operator= is potentially cheaper than a destructor+constructor pair,
usually because it can re-use some allocated memory.
We currently have the advice to prefer:
void fill(string* s);
void use(const string& s);
string s;
for (int i = 0; i < big_number; ++i) {
s.clear();
fill(&s);
use(s);
}
over
string fill();
void use(const string& s);
for (int i = 0; i < big_number; ++i) {
const string s = fill();
use(s);
}
when performance is critical because the former saves on
re-allocations. However, when fill() is also useful outside of loops,
we have to either use the less convenient and less const form:
string s;
fill(&s);
or write a boilerplate overload:
string fill() {
string result;
fill(&result);
return result;
}
const string s = fill();
Rvalue references and move semantics can potentially save on copies
here, but they don't immediately save allocations. But consider the
following definition of fill() instead:
string fill(string&& space = string()) {
space.clear();
// fill space
return move(space);
}
// Maybe needed to disable passing lvalues implicitly?
class Incomplete; Incomplete fill(string&);
Then we can use the same definition of fill() either as:
string s;
for (int i = 0; i < big_number; ++i) {
s = fill(move(s));
use(s);
}
or
const string s = fill();
without ever allocating unnecessary space.
Are there any pitfalls here that I haven't thought of?
Jeffrey Yasskin
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]