Speed of passing a string by value vs. const reference

J

James Kanze

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

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/

Who cares? I want readability and maintainability. Which means
conforming to the usual conventions. If the profiler says that
I must do something else, then I do something else (and I
comment as to why). But otherwise, I write code in the expected
manner, so that the reader isn't surprised.
 
S

SG

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.

I don't think there is a big difference between

string result = cref;
reverse(result.begin(),result.end());

and

string result (cref.rbegin(),cref.rend());

in terms of performance. In both cases you'll have a free store
allocation which is exactly what can be avoided in certain cases by --
oddly enough -- taking the argument by value.

Look Andreas, I simply objected to the simple rule of "always take
class types by ref-to-const" which you had to answer with "Nonsense".
I gave you an example where this rule would mean unnecessary heap
allocation, something your version of flip still does.
Plus moving the argument in the second case will
not be possible if you don't call the function with a temporary,

If it's not a temporary there will be almost no difference between all
the functions. They all create a new string object and make it contain
the reversed string value, something a string usually does by asking
the free store for a chunk of memory which one expects to be a lot
slower than swapping three pointers.
so performance will vary considerably for rather obscure reasons
(and still be slower when not calling with a temporary).

In the case of an Lvalue argument, it might be a little bit slower,
yes. But that's probably nothing compared to an unnecessary free store
allocation which it can save.

I'm actually surprized to see such resistance against rethinking the
"always take a ref-to-const for class types" idea. James made it sound
like removing a "const&" suddently makes the code less maintainable
and readable. I find such a claim rather ridiculous, to be honest.

I stand by what I said.

Cheers!
SG
 
S

SG

Who cares?  I want readability and maintainability.

These are certainly desirable things. But in case you have forgotten:
this thread's title begins with "speed of passing a string...".
Anyhow, I don't see how removing a "const&" from a function's
signature somehow makes code less readable and less maintainable.

Cheers!
SG
 
I

Ian Collins

SG said:
These are certainly desirable things. But in case you have forgotten:
this thread's title begins with "speed of passing a string...".
Anyhow, I don't see how removing a "const&" from a function's
signature somehow makes code less readable and less maintainable.

Possibly because a future maintainer, used to following convention, will
put it back!

I agree with James, follow convention unless profiling shows you should
do otherwise and when you don't, *comment*.

Conventions are just guidelines, not inviolable rules.
 
A

Andreas Dehmel

On May 31, 3:50 pm, Andreas Dehmel wrote:
[...]
I'm actually surprized to see such resistance against rethinking the
"always take a ref-to-const for class types" idea. James made it sound
like removing a "const&" suddently makes the code less maintainable
and readable. I find such a claim rather ridiculous, to be honest.

I concede that there are _very_ special cases where pass by value can
be faster than const reference and maybe there are even some with any
real world relevance. For this to be true, however, you also need
_very_ specific prerequisites, like in your example returning a
modified version of a temporary argument. In other words: you really
have to know what you're doing and what the compiler is doing for
this to work, otherwise you're likely to make things much worse. Not
"early-optimization worse", _much_ worse than that. Now, people who
really know what they're doing don't ask how they're supposed to
pass strings in newsgroups. And you know what happens when people
who don't really know what they're doing get told pass-by-value
might be just as fast or faster? They always pass by value because
it's convenient and that's what they read some "expert" saying
somewhere; hell, they might even do it for all types, even ones
that don't have move semantics to begin with. I've seen this sort
of thing happen often enough. And I hope I don't have to tell you
what a colossal mess this will result in.

So due to this I stand by the current guideline "always pass class-
types by const reference". We can add "unless you really, really know
what you're doing" as a footnote, but that's true for all guidelines
anyway and the odd rvalue loophole won't change that in the least.



Andreas
 
J

James Kanze

These are certainly desirable things. But in case you have forgotten:
this thread's title begins with "speed of passing a string...".

So this thread is concerned with how to write bad code.
Anyhow, I don't see how removing a "const&" from a function's
signature somehow makes code less readable and less maintainable.

Replacing a simple rule with a more complex one always makes
code less readable and less maintainable. Especially when the
more complex rule depends in internal implementation details.
 
B

Balog Pal

So this thread is concerned with how to write bad code.


Replacing a simple rule with a more complex one always makes
code less readable and less maintainable. Especially when the
more complex rule depends in internal implementation details.

IMO this particular ting should not be a big deal. I have a couple of
documentation-only macros that translate to nothing. Would make the
signature read (BYVAL string s) that states the fact it was an
intentional choice. client code shall not notice any difference from
signature changes between const& and by-value. Same for programmers.

The only involved party I see is implementer of the function.

Those not using sig annotations can do the same using old-fashioned
comment at the implementation site.

Maitainance-wise I fail to see the difference using either approach.
Especially considering it a rare case that fits the 'don't sweat over
the small stuff' category.
 
W

woodbrian77

So this thread is concerned with how to write bad code.

Like it or not, there are a lot of pesky rules to consider
if we aim to write quality software. I'm sympathetic to
SG's talk about rethinking the matter.

I wish I could be of more help in this and other matters,
but am sorry to report that the Minnesota legislature
recently passed a bill that legalizes "gay" marriage.
Like the Mayflower pilgrims who voted with their feet
for a more G-dly society, I'm now thinking about moving
the company to a more conservative and ethical state.
One of the reasons I started Ebenezer Enterprises was I
wasn't willing to work for a company that used part of the
money I helped it make to support immorality. IBM, Intel,
HP, Google, Microsoft, etc. are the Goliath(s) of these
days. They are too full of it to be bothered with a
simple rule about marriage.


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

Bo Persson

I wish I could be of more help in this and other matters,
but am sorry to report that the Minnesota legislature
recently passed a bill that legalizes "gay" marriage.
Like the Mayflower pilgrims who voted with their feet
for a more G-dly society, I'm now thinking about moving
the company to a more conservative and ethical state.
One of the reasons I started Ebenezer Enterprises was I
wasn't willing to work for a company that used part of the
money I helped it make to support immorality. IBM, Intel,
HP, Google, Microsoft, etc. are the Goliath(s) of these
days. They are too full of it to be bothered with a
simple rule about marriage.

They are not forcing you to marry anyone against your will, are they?

So what's the big deal, and how does it affect your ability to answer
IT-related questions?


Bo Persson
 
W

woodbrian77

They are not forcing you to marry anyone against your will, are they?

No, but I would be forced to help pay for the benefits
of what is imo immoral. The legislature in its infinite
wisdom has seen fit to redefine marriage which has been
between a man and woman for thousands of years.
So what's the big deal, and how does it affect your ability to answer
IT-related questions?

The time/money needed to move is a big deal and that
affects my ability to contribute to various matters.

If you are a C++ developer in a US state that still
has the traditional understanding of marriage and would
like to have Ebenezer Enterprises in your backyard,
please let me know.


Brian
Ebenezer Enterprises - Many are the afflictions of the
righteous, but the L-rd delivers him from them all.
http://webEbenezer.net
 
G

Gerhard Fiedler

No, but I would be forced to help pay for the benefits of what is imo
immoral. The legislature in its infinite wisdom has seen fit to
redefine marriage which has been between a man and woman for
thousands of years.

The word "marriage" isn't even known for a thousand years... :)

Gerhard
 
Ö

Öö Tiib

The word "marriage" isn't even known for a thousand years... :)

Joking about short history of English language? We have some older
cultures. It can be argued if institution of marriage predates
recorded history by tens or hundreds of thousands years, also there
are differences in practices involved in different cultures ... but
it certainly is nothing recent.
 
J

James Kanze

IMO this particular ting should not be a big deal. I have a couple of
documentation-only macros that translate to nothing. Would make the
signature read (BYVAL string s) that states the fact it was an
intentional choice. client code shall not notice any difference from
signature changes between const& and by-value. Same for programmers.

It's still added complexity.
The only involved party I see is implementer of the function.

And anyone who has to include the header.
Those not using sig annotations can do the same using old-fashioned
comment at the implementation site.
Maitainance-wise I fail to see the difference using either approach.

Maintainance-wise, you're proposing that the signature of a
function depend on its internal implementation. And you don't
see a difference there?
Especially considering it a rare case that fits the 'don't sweat over
the small stuff' category.

The "don't sweat over the small stuff" is one of the worse
cliches to be proposed. Writing correct programs is all about
paying attention to detail: the small stuff. Herb's early work
explaining the ins and outs of exceptions is fundamental, but a
lot of his later stuff recommends more anti-patterns than
anything else: "use auto whenever possible" (and skip all of the
advantages of C++ type checking), "always use standard smart
pointers" (std::shared_ptr only works if *all* pointers to an
object are shared_ptr. Including 'this'. In the rare cases
where a reference counted pointer is useful, there are better
solutions than std::shared_ptr). "Don't sweat the small stuff"
is another example of an anti-pattern: the real rule would be
more along the lines of "don't ignore any detail, no matter how
small".
 
B

Balog Pal

And anyone who has to include the header.

When I'm client of the function and look at the sig, I'm interested in
the nature of params. It it's pure input param, I could not care less if
it is by val or const&.
Maintainance-wise, you're proposing that the signature of a
function depend on its internal implementation. And you don't
see a difference there?

I meant /significant/ difference. Just because there is no artificial
restriction to do everything in a single way where multiple ways are
usable it does not imply an overall overhead. At least I didn't notice it.
The "don't sweat over the small stuff" is one of the worse
cliches to be proposed. Writing correct programs is all about
paying attention to detail: the small stuff.

Those are not the same concepts. "Small stuff" is CN Parkinson's bike
shed. The thing that is 0.01% of your monetary budget but is happy to
swallow weeks in discussion.

The alternatives we discuss are both correct. That is the detail we must
care about. Choosing one over other will not alter correctness.
Herb's early work
explaining the ins and outs of exceptions is fundamental, but a
lot of his later stuff recommends more anti-patterns than
anything else: "use auto whenever possible"

Well, possibly there are different interpretations of "wherever
possible". And I do use auto in most contexts possible. Finally. It
always bugged me that I must break DRY SPOT in order to fix common
sub-expressions. The occasions where I want to put in the type are just
very very rare. And where in existing code it differns from auto, I
bet over 90% to be error or unintentional.

And where I mean to fix the type I just do that. it does not match the
"wherever possible" case. I see that you might interpret it in a pure
technical way. I do not. Where fixed type is part of the requirement,
coding idea, etc, there it is is not possible to substitute with a joker.
(and skip all of the advantages of C++ type checking),

The checks work fine where the expression is used. Where repeating the
type, well or badly it is not a service.
"always use standard smart pointers"

I missed that advice -- what was the context? Instead of what? It's
probably good idea these days replace boost::shared_ptr to std:: one.
(Just a wild bet, I'm not using either currently or in the past, but for
accidental reasons.)

And unique_ptr finally makes sense for many use cases.

I have no plans to part with my auto_ptrNC and auto_ptrDC (no-copy and
deep-copy versions with same reset/release/get interface and simple
policy) as long as std:: has nothing to offer in the slot, but if that
happened I'd be glad to switch over eventually, and use std:: for new code.
(std::shared_ptr only works if *all* pointers to an
object are shared_ptr. Including 'this'. In the rare cases
where a reference counted pointer is useful, there are better
solutions than std::shared_ptr).

You don;t have to convince me about right tool for the right thing.
"Don't sweat the small stuff"
is another example of an anti-pattern: the real rule would be
more along the lines of "don't ignore any detail, no matter how
small".

You completely misrepresent that one. It's one of the oldest wisdom of
resource allocation to put your effort where it produce the most effect
(one parallel of the 20/80 rule). I'm lazy to fetch the book, but in
Coding Standards where the idea is introduced in item 0 there is a list
and explanation that makes perfect sense.

The detail that fits here is not ignored as being unseen, but refused
the fuss around, being evaluated as insignificant.

And just to avoid misunderstanding: if you have an installed policy that
input params are mandatory to be const&, have it enforced over the code
base and beaten in the culture -- I certainly would not go against it.
It's a working and consistent system. And breaking existing uniformity
is a step downwards.

But if the codebase is diverse to start with or uses guide like I
(hopefully) said earlier, again I would not bother to force it to a
single form.
 
J

Jorgen Grahn

On 02/06/13 22:09, (e-mail address removed) wrote: ....
If you want to discuss something like, I'm sure there are people in this
group ready to argue with you and against you. But please start it as a
new topic, marked [OT], so that those not interested can easily kill the
thread.

No. Post it in some other group. I'm sure there are plenty of groups
where gay marriage, God etc are ontopic.

/Jorgen
(still waiting for my TC++PL4)
 

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
474,102
Messages
2,570,646
Members
47,247
Latest member
GabrieleL2

Latest Threads

Top