Speed of passing a string by value vs. const reference

K

K. Frank

Hello Group!

Let's say I have a function that takes a std::string as an
argument. Are there any rules of thumb for when is is likely
to be more efficient to pass the string by value instead of
const reference?

I understand that the specific details matter such as how big
the string is and how often it is accessed in the function.
I'm wondering if there are any rough guidelines for which
approach is likely to be faster.

Thanks.


K. Frank
 
S

Stefan Ram

K. Frank said:
I understand that the specific details matter such as how big
the string is and how often it is accessed in the function.
I'm wondering if there are any rough guidelines for which
approach is likely to be faster.

»There were two versions of it, one in Lisp and one in
C++. The display subsystem of the Lisp version was faster.
There were various reasons, but an important one was GC:
the C++ code copied a lot of buffers because they got
passed around in fairly complex ways, so it could be quite
difficult to know when one could be deallocated. To avoid
that problem, the C++ programmers just copied. The Lisp
was GCed, so the Lisp programmers never had to worry about
it; they just passed the buffers around, which reduced
both memory use and CPU cycles spent copying.«

<[email protected]>
 
W

woodbrian77

Hello Group!


Let's say I have a function that takes a std::string as an
argument. Are there any rules of thumb for when is is likely
to be more efficient to pass the string by value instead of
const reference?

Not to my knowledge. It's common for functions to take
a std::string as a reference.

Brian
Ebenezer Enterprises
http://webEbenezer.net
 
M

Marcel Müller

Let's say I have a function that takes a std::string as an
argument. Are there any rules of thumb for when is is likely
to be more efficient to pass the string by value instead of
const reference?

It depends on the implementation.
Some std::string implementations use copy on write.
I understand that the specific details matter such as how big
the string is and how often it is accessed in the function.
I'm wondering if there are any rough guidelines for which
approach is likely to be faster.

Passing const references is most of the time faster. In some
implementations it makes no significant difference.


Marcel
 
Ö

Öö Tiib

Let's say I have a function that takes a std::string as an
argument. Are there any rules of thumb for when is is likely
to be more efficient to pass the string by value instead of
const reference?

Yes, when the function would otherwise internally make a copy of
passed in string then pass by value instead. For example:

typedef std::map<std::string,std::string> Translations;

Translations translations;
static std::string const nothing;

std::string const& findTranslation( std::string text )
{
boost::trim(text);
boost::to_upper(text);
auto it = translations.find(text);
if (it == translations.end())
{
return nothing;
}
return it->second;
}

Otherwise always pass 'std::string const&'.

Exception is when you are sure that string is implemented copy on
write on target platform. On such platform it is always beneficial
to pass by value. Copy on write string implementations are rather
exotic at the moment.
 
S

SG

[...] always pass 'std::string const&'.

Exception is [...]

when you have to create a copy of it somewhere during the function
call

Example1:

class foo {
string bar;
public:
explicit foo(string x)
: bar(move(x))
{}
};

Example2:

string flip(string x) {
reverse(begin(x),end(x));
return x;
}

This is totally acceptable because std::string is move-enabled. In
both examples the function-local variable 'x' comes into existence
either by a copy construction, a move construction, or even directly
(copy/move elision). The compiler handles this automatically depending
on the argument expression. In both cases there won't be any
unnecessary copy constructions.

Cheers!
SG
 
Ö

Öö Tiib

[...] always pass 'std::string const&'.

Exception is [...]

when you have to create a copy of it somewhere during the function
call

But that was what I tried to say before first '[...]' you snipped. Does not
it get sort of recursive that way?
 
W

woodbrian77

Yes, when the function would otherwise internally make a copy of
passed in string then pass by value instead. For example:

If you need to make a copy of the string's data, but
not of the string object it probably makes sense to
use a reference.

void SendBuffer::Receive :):std::string const& str)
{
marshalling_integer slen(str.length());
slen.Marshal(*this);
Receive(str.c_str(), slen.value);
}


Brian
Ebenezer Enterprises - In G-d we trust.
http://webEbenezer.net
 
Ö

Öö Tiib

If you need to make a copy of the string's data, but
not of the string object it probably makes sense to
use a reference.

Does not "copy" implicitly mean that the objects are of same type?
Do not people usually say "to convert" instead of "to make copy of
data"?
 
W

woodbrian77

Does not "copy" implicitly mean that the objects are of same type?
Do not people usually say "to convert" instead of "to make copy of
data"?

I'm nitpicking. I think your original post was helpful, but
wanted to point out that another way to interpret your words
exists.
 
K

K. Frank

Hello Group!

Thanks to all for your various replies. This is very
much the kind of guidance I was looking for.


K. Frank
 
J

James Kanze

Let's say I have a function that takes a std::string as an
argument. Are there any rules of thumb for when is is likely
to be more efficient to pass the string by value instead of
const reference?
I understand that the specific details matter such as how big
the string is and how often it is accessed in the function.
I'm wondering if there are any rough guidelines for which
approach is likely to be faster.

The ubiquitous rule is to pass class types by reference to
const, other types by value. Since std:;string is a class type,
convention says to pass it by reference to const, even if with a
well written string class, it won't make a significant
difference.
 
S

SG

The ubiquitous rule is to pass class types by reference to
const, other types by value.  Since std:;string is a class type,
convention says to pass it by reference to const, even if with a
well written string class, it won't make a significant
difference.

Some rules are now outdated in the light of move semantics.
 
A

Andreas Dehmel

Some rules are now outdated in the light of move semantics.

Nonsense. For container types, a move still implies swapping at
least 2-3 pointer-sized members and while this is certainly orders
of magnitude faster than copying the whole thing, there's no way
this'll be faster than simply dereferencing a pointer.



Andreas
 
Ö

Öö Tiib

Nonsense. For container types, a move still implies swapping at
least 2-3 pointer-sized members and while this is certainly orders
of magnitude faster than copying the whole thing, there's no way
this'll be faster than simply dereferencing a pointer.

So what? Parameter is passed once but that dereference may happen
several times during function call. It may add up costing more.
 
Ö

Öö Tiib

It is trivial for the compiler to optimize out this extra dereference as
C++ references cannot be reseated. Or have I misunderstood something?

All optimizations are trivial. It can be optimized by cashing the pointer
in some register. Fine if compiler can reserve a register for a parameter
but registers are often quite limited resource. I was responding to
"nonsense, there's no way" when actual measurements show that there is.
 
S

SG

Nonsense. For container types, a move still implies swapping at
least 2-3 pointer-sized members and while this is certainly orders
of magnitude faster than copying the whole thing, there's no way
this'll be faster than simply dereferencing a pointer.

Compare

string flip(string const& cref) {
string result = cref; // explicit copy,
// might be unnecessary
reverse(result.begin(),result.end());
return result; // NRVO applicable
}

with

string flip(string temp) { // temp might be move-constructed or
// even constructed directly via
// copy/move elision
reverse(temp.begin(),temp.end());
return temp; // implicitly moved
}

You might want to test this with a dummy-string class and count the
number of copy and move constructions in the following example:

int main() {
string foo = flip(flip(flip(flip("hello"))));
}

So, no, it's not nonsense. In situations where you have the choice
between pass-by-value and pass-by-ref-to-const for class types, the
rule "always take a ref-to-const" is obviously not correct anymore.
Note that I'm not saying "always use pass-by-value" either.

You might also want to check Dave Abrahams' article about this with
the provoking title: "Want speed? Pass by value.":
http://cpp-next.com/archive/2009/08/want-speed-pass-by-value/

Cheers!
SG
 
A

Andreas Dehmel

Compare

string flip(string const& cref) {
string result = cref; // explicit copy,
// might be unnecessary
reverse(result.begin(),result.end());
return result; // NRVO applicable
}

with

string flip(string temp) { // temp might be move-constructed or
// even constructed directly via
// copy/move elision
reverse(temp.begin(),temp.end());
return temp; // implicitly moved
}


You're not measuring the overhead of passing the argument one way
or another but the copy constructor in the first case, which is
a completely different issue that can easily be avoided by using
string result(cref.rbegin(), cref.rend()) rather than call reverse
on a copy. I'd call this a pathological textbook example with zero
practical relevance; one can always construct these, that doesn't
mean anything. Plus moving the argument in the second case will
not be possible if you don't call the function with a temporary,
so performance will vary considerably for rather obscure reasons
(and still be slower when not calling with a temporary).



Andreas
 
J

James Kanze

Some rules are now outdated in the light of move semantics.

Or not. The rule was fairly arbitrary to begin with, and move semantics don't
really change that.
 
J

James Kanze

So what? Parameter is passed once but that dereference may happen
several times during function call. It may add up costing more.

As you say: so what? The rule was always arbitrary. It had the
advantage of being simple. Move semantics don't change anything
in this respect. Logically, the rule would be pass by value,
always. But that's not the ubiquitous conventions. The
convention is what it is. It may not be perfect, but it is
ubiquitous. Thus, you need a really strong motive to violate
it.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,766
Messages
2,569,569
Members
45,042
Latest member
icassiem

Latest Threads

Top