Speed of passing a string by value vs. const reference

Discussion in 'C++' started by K. Frank, May 25, 2013.

  1. K. Frank

    K. Frank Guest

    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
    K. Frank, May 25, 2013
    #1
    1. Advertising

  2. K. Frank

    Stefan Ram Guest

    "K. Frank" <> writes:
    >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.«

    <XNOkd.7720$>
    Stefan Ram, May 25, 2013
    #2
    1. Advertising

  3. K. Frank

    Guest

    On Saturday, May 25, 2013 6:22:49 PM UTC, K. Frank wrote:
    > 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
    , May 25, 2013
    #3
  4. On 25.05.2013 20:22, K. Frank wrote:
    > 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
    Marcel Müller, May 25, 2013
    #4
  5. K. Frank

    Öö Tiib Guest

    On Saturday, 25 May 2013 21:22:49 UTC+3, K. Frank wrote:
    > 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.
    Öö Tiib, May 26, 2013
    #5
  6. K. Frank

    SG Guest

    On May 26, 1:11 am, Öö Tiib wrote:

    > [...] 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
    SG, May 26, 2013
    #6
  7. K. Frank

    Öö Tiib Guest

    On Sunday, 26 May 2013 12:04:00 UTC+3, SG wrote:
    > On May 26, 1:11 am, Öö Tiib wrote:
    >
    > > [...] 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?
    Öö Tiib, May 26, 2013
    #7
  8. K. Frank

    Guest

    On Saturday, May 25, 2013 6:11:53 PM UTC-5, Öö Tiib wrote:

    >
    > 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
    , May 26, 2013
    #8
  9. K. Frank

    Öö Tiib Guest

    On Sunday, 26 May 2013 19:56:46 UTC+3, wrote:
    > On Saturday, May 25, 2013 6:11:53 PM UTC-5, Öö Tiib wrote:
    > >
    > > 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.


    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"?
    Öö Tiib, May 26, 2013
    #9
  10. K. Frank

    Guest

    On Sunday, May 26, 2013 6:11:43 PM UTC, Öö Tiib wrote:
    > On Sunday, 26 May 2013 19:56:46 UTC+3, wrote:
    >
    >>
    >> 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"?


    I'm nitpicking. I think your original post was helpful, but
    wanted to point out that another way to interpret your words
    exists.
    , May 26, 2013
    #10
  11. K. Frank

    K. Frank Guest

    Hello Group!

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


    K. Frank
    K. Frank, May 27, 2013
    #11
  12. K. Frank

    James Kanze Guest

    On Saturday, May 25, 2013 7:22:49 PM UTC+1, K. Frank wrote:
    > 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.

    --
    James
    James Kanze, May 29, 2013
    #12
  13. K. Frank

    SG Guest

    On May 29, 11:46 pm, James Kanze wrote:
    > 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.
    SG, May 30, 2013
    #13
  14. On Thu, 30 May 2013 02:06:37 -0700 (PDT)
    SG <> wrote:

    > On May 29, 11:46 pm, James Kanze wrote:
    > > 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.


    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
    --
    Dr. Andreas Dehmel Ceterum censeo
    FLIPME(ed.enilno-t@nouqraz) Microsoft esse delendam
    http://www.zarquon.homepage.t-online.de (Cato the Much Younger)
    Andreas Dehmel, May 30, 2013
    #14
  15. K. Frank

    Öö Tiib Guest

    On Thursday, 30 May 2013 16:28:53 UTC+3, Andreas Dehmel wrote:
    > On Thu, 30 May 2013 02:06:37 -0700 (PDT)
    > SG <> wrote:
    > > On May 29, 11:46 pm, James Kanze wrote:
    > > > 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.

    >
    > 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, May 30, 2013
    #15
  16. K. Frank

    Öö Tiib Guest

    On Thursday, 30 May 2013 22:21:56 UTC+3, Paavo Helde wrote:
    > Öö Tiib <> wrote in news:9af31fe2-0eba-4788-96fd-
    > > So what? Parameter is passed once but that dereference may happen
    > > several times during function call. It may add up costing more.

    >
    > 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.
    Öö Tiib, May 30, 2013
    #16
  17. K. Frank

    SG Guest

    On May 30, 3:28 pm, Andreas Dehmel wrote:
    > On Thu, 30 May 2013 02:06:37 -0700 (PDT)
    > SG <> wrote:
    > > On May 29, 11:46 pm, James Kanze wrote:
    > > > 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.

    >
    > 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
    SG, May 31, 2013
    #17
  18. On Thu, 30 May 2013 17:55:04 -0700 (PDT)
    SG <> wrote:

    > On May 30, 3:28 pm, Andreas Dehmel wrote:
    > > On Thu, 30 May 2013 02:06:37 -0700 (PDT)
    > > SG <> wrote:
    > > > On May 29, 11:46 pm, James Kanze wrote:
    > > > > 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.

    > >
    > > 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'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
    --
    Dr. Andreas Dehmel Ceterum censeo
    FLIPME(ed.enilno-t@nouqraz) Microsoft esse delendam
    http://www.zarquon.homepage.t-online.de (Cato the Much Younger)
    Andreas Dehmel, May 31, 2013
    #18
  19. K. Frank

    James Kanze Guest

    On Thursday, May 30, 2013 10:06:37 AM UTC+1, SG wrote:
    > On May 29, 11:46 pm, James Kanze wrote:
    > > 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.


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

    --
    James
    James Kanze, May 31, 2013
    #19
  20. K. Frank

    James Kanze Guest

    On Thursday, May 30, 2013 7:38:40 PM UTC+1, Öö Tiib wrote:
    > On Thursday, 30 May 2013 16:28:53 UTC+3, Andreas Dehmel wrote:
    > > On Thu, 30 May 2013 02:06:37 -0700 (PDT)
    > > SG <> wrote:
    > > > On May 29, 11:46 pm, James Kanze wrote:
    > > > > 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.


    > > 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.


    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.

    --
    James
    James Kanze, May 31, 2013
    #20
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Victor Bazarov
    Replies:
    25
    Views:
    847
    E. Robert Tisdale
    Mar 23, 2005
  2. Replies:
    11
    Views:
    1,089
  3. Javier
    Replies:
    2
    Views:
    546
    James Kanze
    Sep 4, 2007
  4. George2
    Replies:
    10
    Views:
    580
    Pete Becker
    Dec 17, 2007
  5. 0m
    Replies:
    26
    Views:
    1,093
    Tim Rentsch
    Nov 10, 2008
Loading...

Share This Page