Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pass by value or const reference? [duplicate]

There is a set of good rules to determine whether pass by value or const reference

  • If the function intends to change the argument as a side effect, take it by non-const reference.
  • If the function doesn't modify its argument and the argument is of primitive type, take it by value.
  • Otherwise take it by const reference, except in the following cases: If the function would then need to make a copy of the const reference anyway, take it by value.

For constructor as following, how to determine it?

class A
{
public:
    A(string str) : mStr(str) {} // here which is better, 
                                 // pass by value or const reference?

    void setString(string str)  { mStr = str; } // how about here?

private:
    string mStr;
};
like image 491
user1899020 Avatar asked Sep 06 '13 13:09

user1899020


People also ask

What is the difference between pass by reference and pass by const reference?

From what I understand: when you pass by value, the function makes a local copy of the passed argument and uses that; when the function ends, it goes out of scope. When you pass by const reference, the function uses a reference to the passed argument that can't be modified.

Does const reference make a copy?

Not just a copy; it is also a const copy. So you cannot modify it, invoke any non-const members from it, or pass it as a non-const parameter to any function. If you want a modifiable copy, lose the const decl on protos .

Does passing by value make a copy?

By definition, pass by value means you are making a copy in memory of the actual parameter's value that is passed in, a copy of the contents of the actual parameter.

Is it better to pass by reference or value C++?

Use pass-by-reference if you want to modify the argument value in the calling function. Otherwise, use pass-by-value to pass arguments. The difference between pass-by-reference and pass-by-pointer is that pointers can be NULL or reassigned whereas references cannot.


2 Answers

In this particular case, and assuming C++11 and move construction/assignment for strings, you should take the argument by value and move it to the member for the constructor.

A::A(string str) : mStr(std::move(str)) {}

The case of the setter is a bit trickier and I am not sure whether you really want/need to optimize every bit of it... If you want to optimize the most you could provide two overloads, one taking an rvalue reference and another taking a const lvalue reference. At any rate, the const lvalue reference is probably a good enough approach:

void A::setString(string const& str) { mStr = str; }

Why the difference?

In the case of the constructor, the member is not yet built, so it is going to need to allocate memory. You can move that memory allocation (and actual copying of the data, but that is the leaser cost) to the interface, so that if the caller has a temporary it can be forwarded without an additional memory allocation.

In the case of assignment the things are a bit more complicated. If the current size of the string is large enough to hold the new value, then no allocation is required, but if the string is not large enough, then it will need to reallocate. If the allocation is moved to the interface (by-value argument), it will be executed always even when it is unnecessary. If the allocation is done inside the function (const reference argument) then for a small set of cases (those where the argument is a temporary that is larger then the current buffer) an allocation that could otherwise have been avoided would be done.

like image 195
David Rodríguez - dribeas Avatar answered Sep 25 '22 17:09

David Rodríguez - dribeas


The article you site is not a good reference for software engineering. (It is also likely out of date, given that it talks about move semantics and is dated from 2003.)

The general rule is simple: pass class types by const reference, and other types by value. There are explicit exceptions: in keeping with the conventions of the standard library, it is also usual to pass iterators and functional objects by value.

Anything else is optimization, and shouldn't be undertaken until the profiler says you have to.

like image 30
James Kanze Avatar answered Sep 22 '22 17:09

James Kanze