When should I return by T const&? If I am not going to modify the object, I do not see how it is any different from returning by value. And returning by const reference really just means no copy is made. So when is returning by T const& useful.
There are two reasons why you would prefer to return by const& rather than by value.
The first is semantics. A code which returns something by const& is telling the caller explicitly, "here is a read-only version of what you asked for. If you want to store it permanently, or make changes to it, you are responsible for making a copy of it." The semantics of this return type are quite clear, and easily enforced.
The second is optimization. By returning something by-value, you remove some optimization opportunities from the compiler. That is not to say that returning by-value is less efficient than returning by const& (in fact, in cases the opposite might be true -- consider a function that returns a char on a 64-bit system). It simply means you remove one of the tools from the compiler's optimization toolbox. There is another tool there to replace it -- namely, inlining the call along with copy elision -- so this might be a wash. It all depends on context.
I mention "semantics" as the first reason because I consider it to be the most important. There are so many variables with optimization and so many moving parts that it's often hard to know just what optimizations the compiler will be able to employ and when. One thing is certian all the time however -- clear semantics are more easily understood by humans than muddled semantics.
A common case where you'd return const T& is a const getter member function:
T& get() { return m_some_private_member; }
const T& get() const { return m_some_private_member; }
In this case you often don't want to make a copy - you just want to return a reference to some object, and for the sake of const-correctness you may also need to provide a const getter.
When you have a sufficiently stable object.
One trivial case is for a collection that returns the content that way. Kinda the primary job description.
For nonconst & another usual case is to return what you got in arguments (including the hidden this pointer). That could apply to const& in a similar way, but be aware of risks, when your param was bound to a temporary that will disappear in short time. Would work better if you got & and return const& after changing the content.
You can return reference to a data member, but it fits the "do not leak your guts" guideline.
In any case if you return ref, you must provide documentation to the client on the validity. If you start working out that description, you will discover whether it makes sense in the first place.
Another obvious case is identity objects, that can (or supposed) not to be copied. It make sense to have to accessors, one returning const& for mainstream use and another with write access.
For the very reason you specified: no copy is made.
If you're returning a large object, it is much more efficient to return a const reference than a copy of the object.
Not making a copy is more efficient, especially for complex types, or types that do a lot of work in their copy constructor.
So you can avoid you function being misused as the one below does?
class A
{
int x;
public:
int show()
{
return x;
}
A(int a)
{
x = a;
}
A const& operator+(A& inp)
{
inp.x = this->x + inp.x;
return inp;
}
};
int main()
{
A a(1),b(2),c(0),d(420);
a + b = d;
std::cout<<b.show();
}
This gives, 420 as output. The overload is supposed to be used as d = a + b, but there is nothing stopping the returned reference to be assigned a another object.
If you make the return type of the function as A const& The returned reference is constant and cant be assigned any other object. Hence the operator has to be used only as d = a + b and not allowing a + b = d etc.
g++ gives error error: passing ‘const A’ as ‘this’ argument of ‘A& A::operator=(const A&)’ discards qualifiers and effectively prevents such misuse.
Related
I heard a recent talk by Herb Sutter who suggested that the reasons to pass std::vector and std::string by const & are largely gone. He suggested that writing a function such as the following is now preferable:
std::string do_something ( std::string inval )
{
std::string return_val;
// ... do stuff ...
return return_val;
}
I understand that the return_val will be an rvalue at the point the function returns and can therefore be returned using move semantics, which are very cheap. However, inval is still much larger than the size of a reference (which is usually implemented as a pointer). This is because a std::string has various components including a pointer into the heap and a member char[] for short string optimization. So it seems to me that passing by reference is still a good idea.
Can anyone explain why Herb might have said this?
The reason Herb said what he said is because of cases like this.
Let's say I have function A which calls function B, which calls function C. And A passes a string through B and into C. A does not know or care about C; all A knows about is B. That is, C is an implementation detail of B.
Let's say that A is defined as follows:
void A()
{
B("value");
}
If B and C take the string by const&, then it looks something like this:
void B(const std::string &str)
{
C(str);
}
void C(const std::string &str)
{
//Do something with `str`. Does not store it.
}
All well and good. You're just passing pointers around, no copying, no moving, everyone's happy. C takes a const& because it doesn't store the string. It simply uses it.
Now, I want to make one simple change: C needs to store the string somewhere.
void C(const std::string &str)
{
//Do something with `str`.
m_str = str;
}
Hello, copy constructor and potential memory allocation (ignore the Short String Optimization (SSO)). C++11's move semantics are supposed to make it possible to remove needless copy-constructing, right? And A passes a temporary; there's no reason why C should have to copy the data. It should just abscond with what was given to it.
Except it can't. Because it takes a const&.
If I change C to take its parameter by value, that just causes B to do the copy into that parameter; I gain nothing.
So if I had just passed str by value through all of the functions, relying on std::move to shuffle the data around, we wouldn't have this problem. If someone wants to hold on to it, they can. If they don't, oh well.
Is it more expensive? Yes; moving into a value is more expensive than using references. Is it less expensive than the copy? Not for small strings with SSO. Is it worth doing?
It depends on your use case. How much do you hate memory allocations?
Are the days of passing const std::string & as a parameter over?
No. Many people take this advice (including Dave Abrahams) beyond the domain it applies to, and simplify it to apply to all std::string parameters -- Always passing std::string by value is not a "best practice" for any and all arbitrary parameters and applications because the optimizations these talks/articles focus on apply only to a restricted set of cases.
If you're returning a value, mutating the parameter, or taking the value, then passing by value could save expensive copying and offer syntactical convenience.
As ever, passing by const reference saves much copying when you don't need a copy.
Now to the specific example:
However inval is still quite a lot larger than the size of a reference (which is usually implemented as a pointer). This is because a std::string has various components including a pointer into the heap and a member char[] for short string optimization. So it seems to me that passing by reference is still a good idea. Can anyone explain why Herb might have said this?
If stack size is a concern (and assuming this is not inlined/optimized), return_val + inval > return_val -- IOW, peak stack usage can be reduced by passing by value here (note: oversimplification of ABIs). Meanwhile, passing by const reference can disable the optimizations. The primary reason here is not to avoid stack growth, but to ensure the optimization can be performed where it is applicable.
The days of passing by const reference aren't over -- the rules just more complicated than they once were. If performance is important, you'll be wise to consider how you pass these types, based on the details you use in your implementations.
Short answer: NO! Long answer:
If you won't modify the string (treat is as read-only), pass it as const ref&.(the const ref& obviously needs to stay within scope while the function that uses it executes)
If you plan to modify it or you know it will get out of scope (threads), pass it as a value, don't copy the const ref& inside your function body.
There was a post on cpp-next.com called "Want speed, pass by value!". The TL;DR:
Guideline: Don’t copy your function arguments. Instead, pass them by value and let the compiler do the copying.
TRANSLATION of ^
Don’t copy your function arguments --- means: if you plan to modify the argument value by copying it to an internal variable, just use a value argument instead.
So, don't do this:
std::string function(const std::string& aString){
auto vString(aString);
vString.clear();
return vString;
}
do this:
std::string function(std::string aString){
aString.clear();
return aString;
}
When you need to modify the argument value in your function body.
You just need to be aware how you plan to use the argument in the function body. Read-only or NOT... and if it sticks within scope.
This highly depends on the compiler's implementation.
However, it also depends on what you use.
Lets consider next functions :
bool foo1( const std::string v )
{
return v.empty();
}
bool foo2( const std::string & v )
{
return v.empty();
}
These functions are implemented in a separate compilation unit in order to avoid inlining. Then :
1. If you pass a literal to these two functions, you will not see much difference in performances. In both cases, a string object has to be created
2. If you pass another std::string object, foo2 will outperform foo1, because foo1 will do a deep copy.
On my PC, using g++ 4.6.1, I got these results :
variable by reference: 1000000000 iterations -> time elapsed: 2.25912 sec
variable by value: 1000000000 iterations -> time elapsed: 27.2259 sec
literal by reference: 100000000 iterations -> time elapsed: 9.10319 sec
literal by value: 100000000 iterations -> time elapsed: 8.62659 sec
Unless you actually need a copy it's still reasonable to take const &. For example:
bool isprint(std::string const &s) {
return all_of(begin(s),end(s),(bool(*)(char))isprint);
}
If you change this to take the string by value then you'll end up moving or copying the parameter, and there's no need for that. Not only is copy/move likely more expensive, but it also introduces a new potential failure; the copy/move could throw an exception (e.g., allocation during copy could fail) whereas taking a reference to an existing value can't.
If you do need a copy then passing and returning by value is usually (always?) the best option. In fact I generally wouldn't worry about it in C++03 unless you find that extra copies actually causes a performance problem. Copy elision seems pretty reliable on modern compilers. I think people's skepticism and insistence that you have to check your table of compiler support for RVO is mostly obsolete nowadays.
In short, C++11 doesn't really change anything in this regard except for people that didn't trust copy elision.
Almost.
In C++17, we have basic_string_view<?>, which brings us down to basically one narrow use case for std::string const& parameters.
The existence of move semantics has eliminated one use case for std::string const& -- if you are planning on storing the parameter, taking a std::string by value is more optimal, as you can move out of the parameter.
If someone called your function with a raw C "string" this means only one std::string buffer is ever allocated, as opposed to two in the std::string const& case.
However, if you don't intend to make a copy, taking by std::string const& is still useful in C++14.
With std::string_view, so long as you aren't passing said string to an API that expects C-style '\0'-terminated character buffers, you can more efficiently get std::string like functionality without risking any allocation. A raw C string can even be turned into a std::string_view without any allocation or character copying.
At that point, the use for std::string const& is when you aren't copying the data wholesale, and are going to pass it on to a C-style API that expects a null terminated buffer, and you need the higher level string functions that std::string provides. In practice, this is a rare set of requirements.
std::string is not Plain Old Data(POD), and its raw size is not the most relevant thing ever. For example, if you pass in a string which is above the length of SSO and allocated on the heap, I would expect the copy constructor to not copy the SSO storage.
The reason this is recommended is because inval is constructed from the argument expression, and thus is always moved or copied as appropriate- there is no performance loss, assuming that you need ownership of the argument. If you don't, a const reference could still be the better way to go.
I've copy/pasted the answer from this question here, and changed the names and spelling to fit this question.
Here is code to measure what is being asked:
#include <iostream>
struct string
{
string() {}
string(const string&) {std::cout << "string(const string&)\n";}
string& operator=(const string&) {std::cout << "string& operator=(const string&)\n";return *this;}
#if (__has_feature(cxx_rvalue_references))
string(string&&) {std::cout << "string(string&&)\n";}
string& operator=(string&&) {std::cout << "string& operator=(string&&)\n";return *this;}
#endif
};
#if PROCESS == 1
string
do_something(string inval)
{
// do stuff
return inval;
}
#elif PROCESS == 2
string
do_something(const string& inval)
{
string return_val = inval;
// do stuff
return return_val;
}
#if (__has_feature(cxx_rvalue_references))
string
do_something(string&& inval)
{
// do stuff
return std::move(inval);
}
#endif
#endif
string source() {return string();}
int main()
{
std::cout << "do_something with lvalue:\n\n";
string x;
string t = do_something(x);
#if (__has_feature(cxx_rvalue_references))
std::cout << "\ndo_something with xvalue:\n\n";
string u = do_something(std::move(x));
#endif
std::cout << "\ndo_something with prvalue:\n\n";
string v = do_something(source());
}
For me this outputs:
$ clang++ -std=c++11 -stdlib=libc++ -DPROCESS=1 test.cpp
$ a.out
do_something with lvalue:
string(const string&)
string(string&&)
do_something with xvalue:
string(string&&)
string(string&&)
do_something with prvalue:
string(string&&)
$ clang++ -std=c++11 -stdlib=libc++ -DPROCESS=2 test.cpp
$ a.out
do_something with lvalue:
string(const string&)
do_something with xvalue:
string(string&&)
do_something with prvalue:
string(string&&)
The table below summarizes my results (using clang -std=c++11). The first number is the number of copy constructions and the second number is the number of move constructions:
+----+--------+--------+---------+
| | lvalue | xvalue | prvalue |
+----+--------+--------+---------+
| p1 | 1/1 | 0/2 | 0/1 |
+----+--------+--------+---------+
| p2 | 1/0 | 0/1 | 0/1 |
+----+--------+--------+---------+
The pass-by-value solution requires only one overload but costs an extra move construction when passing lvalues and xvalues. This may or may not be acceptable for any given situation. Both solutions have advantages and disadvantages.
Herb Sutter is still on record, along with Bjarne Stroustroup, in recommending const std::string& as a parameter type; see https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#Rf-in .
There is a pitfall not mentioned in any of the other answers here: if you pass a string literal to a const std::string& parameter, it will pass a reference to a temporary string, created on-the-fly to hold the characters of the literal. If you then save that reference, it will be invalid once the temporary string is deallocated. To be safe, you must save a copy, not the reference. The problem stems from the fact that string literals are const char[N] types, requiring promotion to std::string.
The code below illustrates the pitfall and the workaround, along with a minor efficiency option -- overloading with a const char* method, as described at Is there a way to pass a string literal as reference in C++.
(Note: Sutter & Stroustroup advise that if you keep a copy of the string, also provide an overloaded function with a && parameter and std::move() it.)
#include <string>
#include <iostream>
class WidgetBadRef {
public:
WidgetBadRef(const std::string& s) : myStrRef(s) // copy the reference...
{}
const std::string& myStrRef; // might be a reference to a temporary (oops!)
};
class WidgetSafeCopy {
public:
WidgetSafeCopy(const std::string& s) : myStrCopy(s)
// constructor for string references; copy the string
{std::cout << "const std::string& constructor\n";}
WidgetSafeCopy(const char* cs) : myStrCopy(cs)
// constructor for string literals (and char arrays);
// for minor efficiency only;
// create the std::string directly from the chars
{std::cout << "const char * constructor\n";}
const std::string myStrCopy; // save a copy, not a reference!
};
int main() {
WidgetBadRef w1("First string");
WidgetSafeCopy w2("Second string"); // uses the const char* constructor, no temp string
WidgetSafeCopy w3(w2.myStrCopy); // uses the String reference constructor
std::cout << w1.myStrRef << "\n"; // garbage out
std::cout << w2.myStrCopy << "\n"; // OK
std::cout << w3.myStrCopy << "\n"; // OK
}
OUTPUT:
const char * constructor
const std::string& constructor
Second string
Second string
See “Herb Sutter "Back to the Basics! Essentials of Modern C++ Style”. Among other topics, he reviews the parameter passing advice that’s been given in the past, and new ideas that come in with C++11 and specifically looks at the idea of passing strings by value.
The benchmarks show that passing std::strings by value, in cases where the function will copy it in anyway, can be significantly slower!
This is because you are forcing it to always make a full copy (and then move into place), while the const& version will update the old string which may reuse the already-allocated buffer.
See his slide 27: For “set” functions, option 1 is the same as it always was. Option 2 adds an overload for rvalue reference, but this gives a combinatorial explosion if there are multiple parameters.
It is only for “sink” parameters where a string must be created (not have its existing value changed) that the pass-by-value trick is valid. That is, constructors in which the parameter directly initializes the member of the matching type.
If you want to see how deep you can go in worrying about this, watch Nicolai Josuttis’s presentation and good luck with that (“Perfect — Done!” n times after finding fault with the previous version. Ever been there?)
This is also summarized as ⧺F.15 in the Standard Guidelines.
update
Generally, you want to declare "string" parameters as std::string_view (by value). This allows you to pass an existing std::string object as efficiently as with const std::string&, and also pass a lexical string literal (like "hello!") without copying it, and pass objects of type string_view which is necessary now that those are in the ecosystem too.
The exception is when the function needs an actual std::string instance, in order to pass to another function that's declared to take const std::string&.
IMO using the C++ reference for std::string is a quick and short local optimization, while using passing by value could be (or not) a better global optimization.
So the answer is: it depends on circumstances:
If you write all the code from the outside to the inside functions, you know what the code does, you can use the reference const std::string &.
If you write the library code or use heavily library code where strings are passed, you likely gain more in global sense by trusting std::string copy constructor behavior.
As #JDługosz points out in the comments, Herb gives other advice in another (later?) talk, see roughly from here: https://youtu.be/xnqTKD8uD64?t=54m50s.
His advice boils down to only using value parameters for a function f that takes so-called sink arguments, assuming you will move construct from these sink arguments.
This general approach only adds the overhead of a move constructor for both lvalue and rvalue arguments compared to an optimal implementation of f tailored to lvalue and rvalue arguments respectively. To see why this is the case, suppose f takes a value parameter, where T is some copy and move constructible type:
void f(T x) {
T y{std::move(x)};
}
Calling f with an lvalue argument will result in a copy constructor being called to construct x, and a move constructor being called to construct y. On the other hand, calling f with an rvalue argument will cause a move constructor to be called to construct x, and another move constructor to be called to construct y.
In general, the optimal implementation of f for lvalue arguments is as follows:
void f(const T& x) {
T y{x};
}
In this case, only one copy constructor is called to construct y. The optimal implementation of f for rvalue arguments is, again in general, as follows:
void f(T&& x) {
T y{std::move(x)};
}
In this case, only one move constructor is called to construct y.
So a sensible compromise is to take a value parameter and have one extra move constructor call for either lvalue or rvalue arguments with respect to the optimal implementation, which is also the advice given in Herb's talk.
As #JDługosz pointed out in the comments, passing by value only makes sense for functions that will construct some object from the sink argument. When you have a function f that copies its argument, the pass-by-value approach will have more overhead than a general pass-by-const-reference approach. The pass-by-value approach for a function f that retains a copy of its parameter will have the form:
void f(T x) {
T y{...};
...
y = std::move(x);
}
In this case, there is a copy construction and a move assignment for an lvalue argument, and a move construction and move assignment for an rvalue argument. The most optimal case for an lvalue argument is:
void f(const T& x) {
T y{...};
...
y = x;
}
This boils down to an assignment only, which is potentially much cheaper than the copy constructor plus move assignment required for the pass-by-value approach. The reason for this is that the assignment might reuse existing allocated memory in y, and therefore prevent (de)allocations, whereas the copy constructor will usually allocate memory.
For an rvalue argument the most optimal implementation for f that retains a copy has the form:
void f(T&& x) {
T y{...};
...
y = std::move(x);
}
So, only a move assignment in this case. Passing an rvalue to the version of f that takes a const reference only costs an assignment instead of a move assignment. So relatively speaking, the version of f taking a const reference in this case as the general implementation is preferable.
So in general, for the most optimal implementation, you will need to overload or do some kind of perfect forwarding as shown in the talk. The drawback is a combinatorial explosion in the number of overloads required, depending on the number of parameters for f in case you opt to overload on the value category of the argument. Perfect forwarding has the drawback that f becomes a template function, which prevents making it virtual, and results in significantly more complex code if you want to get it 100% right (see the talk for the gory details).
The problem is that "const" is a non-granular qualifier. What is usually meant by "const string ref" is "don't modify this string", not "don't modify the reference count". There is simply no way, in C++, to say which members are "const". They either all are, or none of them are.
In order to hack around this language issue, STL could allow "C()" in your example to make a move-semantic copy anyway, and dutifully ignore the "const" with regard to the reference count (mutable). As long as it was well-specified, this would be fine.
Since STL doesn't, I have a version of a string that const_casts<> away the reference counter (no way to retroactively make something mutable in a class hierarchy), and - lo and behold - you can freely pass cmstring's as const references, and make copies of them in deep functions, all day long, with no leaks or issues.
Since C++ offers no "derived class const granularity" here, writing up a good specification and making a shiny new "const movable string" (cmstring) object is the best solution I've seen.
I came across the following code:
class MyClass {
// various stuff including ...
double *myarray;
double &operator() (const int n){
return myarray[n];
}
double operator() (const int n) const {
return myarray[n];
}
// various other stuff ...
}
So what is the practical difference in those two overloads of "()"? I mean, I know "The first one returns a reference to a double and the second one returns a double," but what does this mean practically? When would I use the one and when would I use the other? The second one (returning a double) seems pretty safe and straightforward. Is the first one ever dangerous in some way?
They differ in that first one allows you to modify your array element, while the second one only returns value, so you can:
with: double &operator()
MyClass mm;
mm(1) = 12;
but also:
std::cout << mm(1);
with: double operator()
// mm(1) = 12; // this does not compile
std::cout << mm(1); // this is ok
also, returning a reference is more common when using operator[], like when you use std::vector::operator[].
btw. its common to have two versions of operator() - one const and second non-const. Const version will be called on const objects, while the second one on non const. But usually their signature is :
double& operator() (const int n);
const double& operator() (const int n) const;
In general, the difference between pointers and references is that pointers can be changed and can also point to nullptr, i.e. to nothing. References are fixed.
In this example, though, operator() does not return a reference but a copy of the value, i.e. changing the value retrieved that way does not change the double in the class.
If it truly returned a double&, then you could use both of these methods interchangeably (of course with different notations in the usage), and offering both would merely be a welcome convenience for the user of this class.
what does this mean practically?
It means that the second method returns by-value, i.e. it makes a copy of the array-item/double and returns that copy to the caller. The first method returns by-reference, i.e. it doesn't make a copy of the double, but rather returns a reference to the original/in-the-array double's location, which the calling code can then use to directly access the in-the-array double, if it wants to. (if it helps, the indirection semantics of the returned reference are somewhat like pointer semantics, except with a syntax that is more similar to the traditional C/C++ by-value functionality)
When would I use the one and when would I use the other?
The by-value method is safer, since there is less chance of invoking undefined behavior; the by-reference method gives you some more flexibility (i.e. the caller could then update the item in the array by writing to the reference he received as a return value) and it might be more efficient in some situations (e.g. returning a reference avoids the need to copy the object, which could be an expensive operation if the object is large or complex). For a small object like a double, returning by-value is likely more efficient than returning by-reference.
Is the [by-reference method] ever dangerous in some way?
It can be -- for example, if you were to return a reference to an automatic/stack variable, that would cause undefined behavior, since the variable would be destroyed before the calling code could use it:
double & dont_ever_do_this()
{
double x = 5.0; // x will be destroyed as this method returns!
return x; // so returning a reference to x is a silly thing to do
}
Similarly, in your MyClass example, if the caller holds on to the returned reference and then tries to use it after myarray has been deleted, the caller will be reading from (or writing to) a memory location that is no longer valid, and that will cause undefined behavior (read: Bad Things) to happen.
And of course returning a non-const reference means the caller has the ability to change the contents of the returned array item without your class being aware of it, which might not be something you want to allow.
You can see value categories from this link.
http://en.cppreference.com/w/cpp/language/value_category
In double& operator() case you have lvalue expression and can use like lvalue (for assignment, print etc.)
MyClass class;
class(7) = 21;
or
std::cout << class(7);
And in double operator() const case you have rvalue expression.
In this case you also can use it with const object.
I have two versions of the same static member function: one takes a pointer-to-const parameter and that takes a pointer-to-non-const parameter. I want to avoid code duplication.
After reading some stack overflow questions (these were all about non-static member functions though) I came up with this:
class C {
private:
static const type* func(const type* x) {
//long code
}
static type* func(type* x) {
return const_cast<type*>(func(static_cast<const type*>(x)));
}
public:
//some code that uses these functions
};
(I know juggling with pointers is generally a bad idea, but I'm implementing a data structure.)
I found some code in libstdc++ that looks like this:
NOTE: these are not member functions
static type* local_func(type* x)
{
//long code
}
type* func(type* x)
{
return local_func(x);
}
const type* func(const type* x)
{
return local_func(const_cast<type*>(x));
}
In the first approach the code is in a function that takes a pointer-to-const parameter.
In the second approach the code is in a function that takes a pointer-to-non-const parameter.
Which approach should generally be used? Are both correct?
The most important rule is that an interface function (public method, a free function other than one in a detail namespace, etc), should not cast away the constness of its input. Scott Meyer was one of the first to talk about preventing duplication using const_cast, here's a typical example (How do I remove code duplication between similar const and non-const member functions?):
struct C {
const char & get() const {
return c;
}
char & get() {
return const_cast<char &>(static_cast<const C &>(*this).get());
}
char c;
};
This refers to instance methods rather than static/free functions, but the principle is the same. You notice that the non-const version adds const to call the other method (for an instance method, the this pointer is the input). It then casts away constness at the end; this is safe because it knows the original input was not const.
Implementing this the other way around would be extremely dangerous. If you cast away constness of a function parameter you receive, you are taking a big risk in UB if the object passed to you is actually const. Namely, if you call any methods that actually mutate the object (which is very easy to do by accident now that you've cast away constness), you can easily get UB:
C++ standard, section § 5.2.11/7 [const cast]
[ Note: Depending on the type of the object, a write operation through the pointer, lvalue or pointer to data member resulting from a
const_cast that casts away a const-qualifier may produce undefined
behavior. —end note ]
It's not as bad in private methods/implementation functions because perhaps you carefully control how/when its called, but why do it this way? It's more dangerous to no benefit.
Conceptually, it's often the case that when you have a const and non-const version of the same function, you are just passing along internal references of the object (vector::operator[] is a canonical example), and not actually mutating anything, which means that it will be safe either way you write it. But it's still more dangerous to cast away the constness of the input; although you might be unlikely to mess it up yourself, imagine a team setting where you write it the wrong way around and it works fine, and then someone changes the implementation to mutate something, giving you UB.
In summary, in many cases it may not make a practical difference, but there is a correct way to do it that's strictly better than the alternative: add constness to the input, and remove constness from the output.
I have actually only ever seen your first version before, so from my experience it is the more common idiom.
The first version seems correct to me while the second version can result in undefined behavior if (A) you pass an actual const object to the function and (B) the long code writes to that object. Given that in the first case the compiler will tell you if you're trying to write to the object I would never recommend option 2 as it is. You could consider a standalone function that takes/returns const however.
Quite new to C++. I have seen people usually pass objects by reference in operator overloading. Well, I can't figure out when it is really necessary. As in the code below, if I remove ampersand in declaration of object c1 and c2 in operator+, still I'll get the same result. Is there any reason to pass-by-reference in this case when we do not want to modify c1 or c2?
#include <iostream>
class Keys
{
private:
int m_nKeys;
public:
Keys(int nKeys) { m_nKeys = nKeys; }
friend Keys operator+(const Keys &c1, const Keys &c2);
int GetKeys() { return m_nKeys; }
};
Keys operator+(const Keys &c1, const Keys &c2)
{
return Keys(c1.m_nKeys + c2.m_nKeys);
}
int main()
{
Keys cKeys1(6);
Keys cKeys2(8);
Keys cKeysSum = cKeys1 + cKeys2;
std::cout << "There are " << cKeysSum.GetKeys() << " Keys." << std::endl;
system("PAUSE");
return 0;
}
Operators are just like ordinary functions, just with "fancy" names :)
(e.g. operator+() instead of sum())
So, the same parameter passing rules that you apply to functions, can be applied to overloaded operators as well.
In particular, when you have a parameter that is not cheap to copy (e.g. an int, a float, are examples of cheap to copy parameters; a std::vector, a std::string, are examples of not cheap to copy parameters), and you observe this parameter inside your method (i.e. it's an input read-only parameter), then you can pass it by const reference (const &).
In this way, basically it's just like the address of the original argument is passed to the function, so there is no deep-copy involved. Deep-copies can be very expensive, e.g. think of a vector with a big number of elements.
So, to recap, you pass by const reference when:
the parameter just is not cheap to copy (e.g. for ints, float, etc. just
don't bother: passing by value is just fine)
the parameter is observed in the function/operator implementation
(i.e. it's an input read-only parameter)
If you pass by reference then there is no copy of the object made, which for more complicated classes could greatly improve performance.
In this case the performance cost may be marginal, and it's conceivable the compiler could optimise it all out, but it's still worth doing. Later the Keys class may change into something more complex.
Advantages of passing by reference:
It allows us to have the function change the value of the argument, which is sometimes useful.
Because a copy of the argument is not made, it is fast, even when used with large structs or classes.
We can pass by const reference to avoid unintentional changes.
We can return multiple values from a function.
Disadvantages of passing by reference:
Because a non-const reference can not be made to a literal or an expression, reference arguments must be normal variables.
It can be hard to tell whether a parameter passed by reference is meant to be input, output, or both.
It’s impossible to tell from the function call that the argument may change. An argument passed by value and passed by reference looks the same. We can only tell whether an argument is passed by value or reference by looking at the function declaration. This can lead to situations where the programmer does not realize a function will change the value of the argument.
Because references are typically implemented by C++ using pointers, and dereferencing a pointer is slower than accessing it directly, accessing values passed by reference is slower than accessing values passed by value.
You can read the below:
http://www.cs.fsu.edu/~myers/c++/notes/references.html
Consider a vector of long having 10 million entries in it. If you prototype a function like:
void foo(vector<long> vl)
{
}
It will cause assignment-operator (or copy-constructor) of vector<long> - and that would need to copy all those 10m elements. Later destructor for this temporary object (vl) would de-allocate memory and perform other cleanup. It will definitely impact performance
There are classes, specially around synchronization providers (critical sections etc.), and some smart pointer classes that prevent copy-constructor and/or assignment-operators - so that assignment or object creation doesn't happen by mistake. Though move-constructor or move-assignment-operator may be implemented.
Often times I see transformer functions that will take a parameter by reference, and also return that same parameter as a function's return value.
For example:
std::string& Lowercase(std::string & str){
std::transform(str.begin(), str.end(), str.begin(), ::tolower);
return str;
}
I understand that this is done as a convenience, and I am under the impression that the compiler will optimize for cases when the return value is not actually used. However, I don't believe the compiler can optimize for newly created return values of non-basic types. For example:
std::tuple<int,std::string,float> function(int const& num, std::string const& str, float const& f){
return std::tuple<int,std::string,float>(num,str,f);
}
Constructors could do almost anything, and although the return type isn't used, it does not mean it would be safe to avoid creating the type. However, in this case, it would be advantageous to not create the type when the return value of the function isn't used.
Is there some kind of way to notify the compiler that if the return type is not being used, it's safe to avoid the creation of the type? This would be function specific, and a decision of the programmers; not something that the compiler could figure out on its own.
In the case of function and if the function is not inlined it might not optimize it since it has non trivial constructor. However, if the function is inlined it might optimize the unused return class if it's lifetime affects none of the arguments. Also since tuple is a standard type i believe most compiler will optimize that returned variable.
In general, there are two ways the compiler optimize your code:
(Named) Return value optimization (RVO/NRVO)
R-value reference
RVO
Take following code as example:
struct A {
int v;
};
A foo(int v) {
A a;
a.v = v;
return a;
}
void bar(A& a, int v) {
a.v = v;
}
A f;
f = foo(1);
A b;
bar(b, 1);
In function foo, the variable a is constructed, modify its member v, and returns. In an human-optimized version bar, a is passed in, modified, and gives to caller.
Obviously, f and b are the same.
And if you know more about C++, you will know in returning from foo, result a is copied to outer f, and the dtor of a is called.
The way to make optimized foo into bar is called RVO, it omits the copy of internal a to outer f. Modification directly goes to variable of caller.
Please beware, there are cases RVO won't apply: copy ctor has side effect, multiple returns, etc.
Here is a detailed explaination:
MSDN
CppWiki
RValue
Another way to optimize return value is to use rvalue ctor introduced in C++ 11. Generally speaking, it's like calling std::swap(vector_lhs, vector_rhs) to swap the internal data pointer to avoid deep copy.
Here is a very good article about optimization:
http://cpp-next.com/archive/2009/08/want-speed-pass-by-value/
Last but not least
In Going Native 2013, Andrei Alexandrescu gave a talk about how to write quick C++ code. And pass by reference is faster than rvalue. (Also RVO has some limitations) So if you do care about performance, please use pass by reference.