I'm having some weird behaviour with the following:
using namespace std;
struct Number
{
Number(int init) : a(init) {}
Number() {};
int a;
static Number& getNumber() { return Number(555); }
//Number(const Number& other)
//{
// a = other.a;
//} // I've commented this out you'll see why
};
int main()
{
Number num1; // Is now junk
Number num2; // Is now junk
num2 = Number::getNumber(); // num 2 is still junk
Number num3 = Number::getNumber(); // num3 has been assigned 555.
// If I define my own copy constructor
// (uncomment it), it stays junk.
cout << num3.a;
}
When I make my own copy constructor, whether it takes a const or not, the value coming in in the "other" argument is junk. I don't get this behaviour if the copy constructor is the default one. I tried it on IDEOne using GCC and this code doesn't compile. However on my Visual Studio it runs as I described.
I find it really hard to understand the rules of how long a temporary is still valid. For example, I thought that if getNumber() returns a reference to a local temporary, it's OK if it's assigned directly on the same line. I was wrong.
getNumber has undefined behavior. You are returning a reference to a local object. When the function returns that object is destroyed so now you have a reference to a object that no longer exists. To fix this we can just return by value like
static Number getNumber() { return {555}; }
And now you the number that is returned is directly constructed from the return value.
All function local variables are destroyed after the return value is created but before execution proceeds. That means returning any type of reference or pointer to a local object will leave you with a dangling reference/pointer.
I learned something trying to answer this.
What are the possible ways you could return an object from your static function?
By value
This is usually the correct way. Often the compiler will use a Return-Value-Optimisation or otherwise avoid actually copying the object multiple times. If you're not sure this is probably what you want.
If the default copy constructor isn't sufficient for you, make sure you define your own, remembering to define it to take a const ref argument. If you're using C++11, defining a separate move constructor may be useful.
By non-const reference
This is incorrect because it's a reference (effectively a pointer) to a memory location that used to contain a variable which doesn't exist any more.
It's an error in gcc. It used to be allowed in Visual Studio although I hear it may not be any more. You can compile with compiler option /Za to turn off various microsoft specific extensions if you want to.
By const reference
This is not an error, but is a warning and is undefined behaviour [citation needed]
You can bind a const ref to a temporary object. See Herb Sutter's article: https://herbsutter.com/2008/01/01/gotw-88-a-candidate-for-the-most-important-const/
e.g. "const Number& num = get_number_by_value()" will often return a copy of a temporary object, and elide the copy, and then the temporary object will be bound to the reference and have its lifetime extended in way that works specifically for const ref (but not other ref, or pointers).
However, I just learned now looking it up, that this technically applies to returning a temporary from a function, but that lifetime is not further lengthened if that is then assigned to another const ref.
So your case
Number num = get_number_by_const_ref()
may work ok but
const Number& num = get_number_by_const_ref()
may not.
Return a const reference to a static member variable
This is not usually helpful, but if your class is very expensive to construct (requires a lot of calculation or uses GB of memory) and you want to return a particular instance of it multiple times, you might have a private const static member variable of the class which stores an instance you can return by ref.
Remember, if you have a static member variable containing an instance variable of the class, it needs to be initialised outside the class in a .c file so the constructor function is available.
The function static Number& getNumber() { return Number(555); } creates a temporary Number and returns a reference to it. The temporary object ceases to exist at the end of the function, meaning the reference you are returning now refers to a destroyed object. This is undefined behavior, which means the behavior could be anything, including appearing to work sometimes. The compiler is not required to diagnose this error, but some (such as GCC) do. If you intend to return a mutable reference to a shared instance, declare a static local object in the body of the function and return a reference to it.
static Number& getNumber()
{
static Number my_instance{555};
return my_instance;
}
Related
Consider the following code:
#include <utility>
#include <iostream>
struct object {
object(const object&) = delete;
object(object&&) = delete;
object() {std::clog << "object::object()\n";}
~object() {std::clog << "object::~object()\n";}
void operator()() const {std::clog << "object::operator()()\n";}
};
struct wrapper {
const object& reference;
void operator()() const {reference();}
};
template <class Arg>
wrapper function(Arg&& arg) {
wrapper wrap{std::forward<Arg>(arg)};
return wrap;
}
int main(int argc, char* argv[]) {
wrapper wrap = function(object{}); // Let's call that temporary object x
wrap();
return 0;
}
I am really surprised that it prints:
object::object()
object::~object()
object::operator()()
Question 1: Why is the lifetime of object x not extended past the function call even if a const reference has been bound to it?
Question 2: Is there any way to implement the wrapper so that it would extend the lifetime of x past the function call?
Note: The copy and move constructors of the object have been explicitly deleted to make sure only one instance of it exists.
Why is the lifetime of object x not extended past the function call even if a const reference has been bound to it?
Technically, the lifetime of the object is extended past the function call. It is not however extended past the initialization of wrap. But that's a technicality.
Before we dive in, I'm going to impose a simplification: let's get rid of wrapper. Also, I'm removing the template part because it too is irrelevant:
const object &function(const object &arg)
{
return arg;
}
This changes precisely nothing about the validity of your code.
Given this statement:
const object &obj = function(object{}); // Let's call that temporary object x
What you want is for the compiler to recognize that "object x" and obj refer to the same object, and therefore the temporary's lifetime should be extended.
That's not possible. The compiler isn't guaranteed to have enough information to know that. Why? Because the compiler may only know this:
const object &function(const object &arg);
See, it's the definition of function that associates arg with the return value. If the compiler doesn't have the definition of function, then it cannot know that the object being passed in is the reference being returned. Without that knowledge, it cannot know to extend x's lifetime.
Now, you might say that if function's definition is provided, then the compiler can know. Well, there are complicated chains of logic that might prevent the compiler from knowing at compile time. You might do this:
const object *minimum(const object &lhs, const object &rhs)
{
return lhs < rhs ? lhs : rhs;
}
Well, that returns a reference to one of them, but which one will only be determined based on the runtime values of the object. Whose lifetime should be extended by the caller?
We also don't want the behavior of code to change based on whether the compiler only has a declaration or has a full definition. Either it's always OK to compile the code if it only has a declaration, or it's never OK to compile the code only with a declaration (as in the case of inline, constexpr, or template functions). A declaration may affect performance, but never behavior. And that's good.
Since the compiler may not have the information needed to recognize that a parameter const& lives beyond the lifetime of a function, and even if it has that information it may not be something that can be statically determined, the C++ standard does not permit an implementation to even try to solve the problem. Thus, every C++ user has to recognize that calling functions on temporaries if it returns a reference can cause problems. Even if the reference is hidden inside some other object.
What you want cannot be done. This is one of the reasons why you should not make an object non-moveable at all unless it is essential to its behavior or performance.
As far as I know, the only case the lifetime if extended if for the return value of a function,
struct A { int a; };
A f() { A a { 42 }; return a`}
{
const A &r = f(); // take a reference to a object returned by value
...
// life or r extended to the end of this scope
}
In your code, you pass the reference to the "constructor" of A class. Thus it is your responsability to ensure that the passed object live longer. Thus, your code above contains undefined behavior.
And what you see would probably be the most probable behavior in a class that do not make reference to any member. If you would access object member (including v-table), you would most likely observe a violation access instead.
Having said that, the correct code in your case would be:
int main(int argc, char* argv[])
{
object obj {};
wrapper wrap = function(obj);
wrap();
return 0;
}
Maybe what you want is to move the temporary object into the wrapper:
struct wrapper {
wrapper(object &&o) : obj(std::move(o)) {}
object obj;
void operator()() const {obj();}
};
In any case, the original code does not make much sense because it is build around false assumption and contains undefined behavior.
The life of a temporary object is essentially the end of the expression in which it was created. That is, when processing wrap = function(object{}) is completed.
So in resume:
Answer 1 Because you try to apply lifetime extension to a context other that the one specified in the standard.
Answer 2 As simple as moving the temporary object into a permanent one.
Recently I have been learning about good programming practice in C++ and found out that many programs pass objects to functions by reference so that multiple instances are not created. I have also learned that passing a constant reference prevents the original object from being modified however I do not understand how this works exactly. Shouldn't a constant reference create a new instance because the original object cannot be modified through the reference but the reference can still be used like a separate object? I'm fairly certain that this is not how it works but then, how does it work? Is there something I missed?
I have also learned that passing a constant reference prevents the original object from being modified [...]
Not quite. You are not allowed to modify the object through the const &. In other words, you have read-only access. But nothing natively prevents other code with read-write access (for example the original owner of the referred object) to modify it. You do need to be careful when designing so that such changes do not surprise you.
A constant reference (const&) is similar to a pointer to a constant object. You are allowed to read it through the reference but not modify it. Others, holding a non-const reference can still modify it.
Shouldn't a constant reference create a new instance because the
original object cannot be modified through the reference but the
reference can still be used like a separate object?
It's better to call it a reference to a constant object. This makes it much clearer how the thing works. Calling it the other way around is just confusing because any reference is constant (meaning you can't let it refer to another object after initialization).
So a reference to a constant object is just an additional name for an existing object (like a non-const reference) with the restriction that this name only allows reading from the existing object.
This means that through a reference to a constant object you can:
only read from member variables of the object, but not assign to them, unless a member is marked as mutable
only call methods of the object that are marked as const
Example:
struct Foo
{
int a;
mutable int b;
void SetA( int newA ) { a = newA; }
int GetA() const { return a; }
};
void DoSomething( const Foo& f )
{
// Here, f is just another name for foo, but it imposes some restrictions:
f.a = 42; // compiler error, can't modify member!
f.SetA( 42 ); // compiler error, can't call non-const method!
int x = f.a; // OK, reading is allowed.
f.b = 42; // OK, because b is marked as mutable
int y = f.GetA(); // OK, because GetA() is marked as const
}
int main()
{
Foo foo;
DoSomething( foo );
}
So in c++ if you assign the return value of a function to a const reference then the lifetime of that return value will be the scope of that reference. E.g.
MyClass GetMyClass()
{
return MyClass("some constructor");
}
void OtherFunction()
{
const MyClass& myClass = GetMyClass(); // lifetime of return value is until the end
// of scope due to magic const reference
doStuff(myClass);
doMoreStuff(myClass);
}//myClass is destructed
So it seems that wherever you would normally assign the return value from a function to a const object you could instead assign to a const reference. Is there ever a case in a function where you would want to not use a reference in the assignment and instead use a object? Why would you ever want to write the line:
const MyClass myClass = GetMyClass();
Edit: my question has confused a couple people so I have added a definition of the GetMyClass function
Edit 2: please don't try and answer the question if you haven't read this:
http://herbsutter.com/2008/01/01/gotw-88-a-candidate-for-the-most-important-const/
If the function returns an object (rather than a reference), making a copy in the calling function is necessary [although optimisation steps may be taken that means that the object is written directly into the resulting storage where the copy would end up, according to the "as-if" principle].
In the sample code const MyClass myClass = GetMyClass(); this "copy" object is named myclass, rather than a temporary object that exists, but isn't named (or visible unless you look at the machine-code). In other words, whether you declare a variable for it, or not, there will be a MyClass object inside the function calling GetMyClass - it's just a matter of whether you make it visible or not.
Edit2:
The const reference solution will appear similar (not identical, and this really just written to explain what I mean, you can't actually do this):
MyClass __noname__ = GetMyClass();
const MyClass &myclass = __noname__;
It's just that the compiler generates the __noname__ variable behind the scenes, without actually telling you about it.
By making a const MyClass myclass the object is made visible and it's clear what is going on (and that the GetMyClass is returning a COPY of an object, not a reference to some already existing object).
On the other hand, if GetMyClass does indeed return a reference, then it is certainly the correct thing to do.
IN some compilers, using a reference may even add an extra memory read when the object is being used, since the reference "is a pointer" [yes, I know, the standard doesn't say that, but please before complaining, do me a favour and show me a compiler that DOESN'T implement references as pointers with extra sugar to make them taste sweeter], so to use a reference, the compiler should read the reference value (the pointer to the object) and then read the value inside the object from that pointer. In the case of the non-reference, the object itself is "known" to the compiler as a direct object, not a reference, saving that extra read. Sure, most compilers will optimise such an extra reference away MOST of the time, but it can't always do that.
One reason would be that the reference may confuse other readers of your code. Not everybody is aware of the fact that the lifetime of the object is extended to the scope of the reference.
The semantics of:
MyClass const& var = GetMyClass();
and
MyClass const var = GetMyClass();
are very different. Generally speaking, you would only use the
first when the function itself returns a reference (and is
required to return a reference by its very semantics). And you
know that you need to pay attention to the lifetime of the
object (which is not under your control). You use the second
when you want to own (a copy of) the object. Using the second
in this case is misleading, can lead to surprises (if the
function also returns a reference to an object which is
destructed earlier) and is probably slightly less efficient
(although in practice, I would expect both to generate exactly
the same code if GetMYClass returns by value).
Performance
As most current compilers elide copies (and moves), both version should have about the same efficiency:
const MyClass& rMyClass = GetMyClass();
const MyClass oMyClass = GetMyClass();
In the second case, either a copy or move is required semantically, but it can be elided per [class.copy]/31. A slight difference is that the first one works for non-copyable non-movable types.
It has been pointed out by Mats Petersson and James Kanze that accessing the reference might be slower for some compilers.
Lifetime
References should be valid during their entire scope just like objects with automatic storage are. This "should" of course is meant to be enforced by the programmer. So for the reader IMO there's no differences in the lifetimes implied by them. Although, if there was a bug, I'd probably look for dangling references (not trusting the original code / the lifetime claim for the reference).
In the case GetMyClass could ever be changed (reasonably) to return a reference, you'd have to make sure the lifetime of that object is sufficient, e.g.
SomeClass* p = /* ... */;
void some_function(const MyClass& a)
{
/* much code with many side-effects */
delete p;
a.do_something(); // oops!
}
const MyClass& r = p->get_reference();
some_function(r);
Ownership
A variable directly naming an object like const MyClass oMyClass; clearly states I own this object. Consider mutable members: if you change them later, it's not immediately clear to the reader that's ok (for all changes) if it has been declared as a reference.
Additionally, for a reference, it's not obvious that the object its referring to does not change. A const reference only implies that you won't change the object, not that nobody will change the object(*). A programmer would have to know that this reference is the only way of referring to that object, by looking up the definition of that variable.
(*) Disclaimer: try to avoid unapparent side effects
I don't understand what you want to achieve. The reason that T const& can be bound (on the stack) to a T (by value) which is returned from a function is to make it possible other function can take this temporary as an T const& argument. This prevents you from requirement to create overloads. But the returned value has to be constructed anyway.
But today (with C++11) you can use const auto myClass = GetMyClass();.
Edit:
As an excample of what can happen I will present something:
MyClass version_a();
MyClass const& version_b();
const MyClass var1 =version_a();
const MyClass var2 =version_b();
const MyClass var3&=version_a();
const MyClass var4&=version_b();
const auto var5 =version_a();
const auto var6 =version_b();
var1 is initialised with the result of version_a()
var2 is initialised with a copy of the object to which the reference returned by version_b() belongs
var3 holds a const reference to to the temoprary which is returned and extends its lifetime
var4 is initialised with the reference returned from version_b()
var5 same as var1
var6 same as var4
They are semanticall all different. var3 works for the reason I gave above. Only var5 and var6 store automatically what is returned.
there is a major implication regarding the destructor actually being called. Check Gotw88, Q3 and A3. I put everything in a small test program (Visual-C++, so forgive the stdafx.h)
// Gotw88.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <iostream>
class A
{
protected:
bool m_destroyed;
public:
A() : m_destroyed(false) {}
~A()
{
if (!m_destroyed)
{
std::cout<<"A destroyed"<<std::endl;
m_destroyed=true;
}
}
};
class B : public A
{
public:
~B()
{
if (!m_destroyed)
{
std::cout<<"B destroyed"<<std::endl;
m_destroyed=true;
}
}
};
B CreateB()
{
return B();
}
int _tmain(int argc, _TCHAR* argv[])
{
std::cout<<"Reference"<<std::endl;
{
const A& tmpRef = CreateB();
}
std::cout<<"Value"<<std::endl;
{
A tmpVal = CreateB();
}
return 0;
}
The output of this little program is the following:
Reference
B destroyed
Value
B destroyed
A destroyed
Here a small explanation for the setup. B is derived from A, but both have no virtual destructor (I know this is a WTF, but here it's important). CreateB() returns B by value. Main now calls CreateB and first stores the result of this call in a const reference of type A. Then CreateB is called and the result is stored in a value of type A.
The result is interesting. First - if you store by reference, the correct destructor is called (B), if you store by value, the wrong one is called. Second - if you store in a reference, the destructor is called only once, this means there is only one object. By value results in 2 calls (to different destructors), which means there are 2 objects.
My advice - use the const reference. At least on Visual C++ it results in less copying. If you are unsure about your compiler, use and adapt this test program to check the compiler. How to adapt? Add copy / move constructor and copy-assignment operator.
I quickly added copy & assignment operators for class A & B
A(const A& rhs)
{
std::cout<<"A copy constructed"<<std::endl;
}
A& operator=(const A& rhs)
{
std::cout<<"A copy assigned"<<std::endl;
}
(same for B, just replace every capital A with B)
this results in the following output:
Reference
A constructed
B constructed
B destroyed
Value
A constructed
B constructed
A copy constructed
B destroyed
A destroyed
This confirms the results from above (please note, the A constructed results from B being constructed as B is derived from A and thus As constructor is called whenever Bs constructor is called).
Additional tests: Visual C++ accepts also the non-const reference with the same result (in this example) as the const reference. Additionally, if you use auto as type, the correct destructor is called (of course) and the return value optimization kicks in and in the end it's the same result as the const reference (but of course, auto has type B and not A).
I'm learning C++ and I'm still confused about this. What are the implications of return a value as constant, reference and constant reference in C++ ? For example:
const int exampleOne();
int& exampleTwo();
const int& exampleThree();
Here's the lowdown on all your cases:
• Return by reference: The function call can be used as the left hand side of an assignment. e.g. using operator overloading, if you have operator[] overloaded, you can say something like
a[i] = 7;
(when returning by reference you need to ensure that the object you return is available after the return: you should not return a reference to a local or a temporary)
• Return as constant value: Prevents the function from being used on the left side of an assignment expression. Consider the overloaded operator+. One could write something like:
a + b = c; // This isn't right
Having the return type of operator+ as "const SomeType" allows the return by value and at the same time prevents the expression from being used on the left side of an assignment.
Return as constant value also allows one to prevent typos like these:
if (someFunction() = 2)
when you meant
if (someFunction() == 2)
If someFunction() is declared as
const int someFunction()
then the if() typo above would be caught by the compiler.
• Return as constant reference: This function call cannot appear on the left hand side of an assignment, and you want to avoid making a copy (returning by value). E.g. let's say we have a class Student and we'd like to provide an accessor id() to get the ID of the student:
class Student
{
std::string id_;
public:
const std::string& id() const;
};
const std::string& Student::id()
{
return id_;
}
Consider the id() accessor. This should be declared const to guarantee that the id() member function will not modify the state of the object. Now, consider the return type. If the return type were string& then one could write something like:
Student s;
s.id() = "newId";
which isn't what we want.
We could have returned by value, but in this case returning by reference is more efficient. Making the return type a const string& additionally prevents the id from being modified.
The basic thing to understand is that returning by value will create a new copy of your object. Returning by reference will return a reference to an existing object. NOTE: Just like pointers, you CAN have dangling references. So, don't create an object in a function and return a reference to the object -- it will be destroyed when the function returns, and it will return a dangling reference.
Return by value:
When you have POD (Plain Old Data)
When you want to return a copy of an object
Return by reference:
When you have a performance reason to avoid a copy of the object you are returning, and you understand the lifetime of the object
When you must return a particular instance of an object, and you understand the lifetime of the object
Const / Constant references help you enforce the contracts of your code, and help your users' compilers find usage errors. They do not affect performance.
Returning a constant value isn't a very common idiom, since you're returning a new thing anyway that only the caller can have, so it's not common to have a case where they can't modify it. In your example, you don't know what they're going to do with it, so why should you stop them from modifying it?
Note that in C++ if you don't say that something is a reference or pointer, it's a value so you'll create a new copy of it rather than modifying the original object. This might not be totally obvious if you're coming from other languages that use references by default.
Returning a reference or const reference means that it's actually another object elsewhere, so any modifications to it will affect that other object. A common idiom there might be exposing a private member of a class.
const means that whatever it is can't be modified, so if you return a const reference you can't call any non-const methods on it or modify any data members.
Return by reference.
You can return a reference to some value, such as a class member. That way, you don't create copies. However, you shouldn't return references to values in a stack, as that results in undefined behaviour.
#include <iostream>
using namespace std;
class A{
private: int a;
public:
A(int num):a(num){}
//a to the power of 4.
int& operate(){
this->a*=this->a;
this->a*=this->a;
return this->a;
}
//return constant copy of a.
const int constA(){return this->a;}
//return copy of a.
int getA(){return this->a;}
};
int main(){
A obj(3);
cout <<"a "<<obj.getA()<<endl;
int& b=obj.operate(); //obj.operate() returns a reference!
cout<<"a^4 "<<obj.getA()<<endl;
b++;
cout<<"modified by b: "<<obj.getA()<<endl;
return 0;
}
b and obj.a "point" to the same value, so modifying b modifies the value of obj.a.
$./a.out
a 3
a^4 81
modified by b: 82
Return a const value.
On the other hand, returning a const value indicates that said value cannot be modified. It should be remarked that the returned value is a copy.:
For example,
constA()++;
would result in a compilation error, since the copy returned by constA() is constant. But this is just a copy, it doesn't imply that A::a is constant.
Return a const reference.
This is similiar to returning a const value, except that no copy is return, but a reference to the actual member. However, it cant be modified.
const int& refA(){return this->a;}
const int& b = obj.refA();
b++;
will result in a compilation error.
const int exampleOne();
Returns a const copy of some int. That is, you create a new int which may not be modified. This isn't really useful in most cases because you're creating a copy anyway, so you typically don't care if it gets modified. So why not just return a regular int?
It may make a difference for more complex types, where modifying them may have undesirable sideeffects though. (Conceptually, let's say a function returns an object representing a file handle. If that handle is const, the file is read-only, otherwise it can be modified. Then in some cases it makes sense for a function to return a const value. But in general, returning a const value is uncommon.
int& exampleTwo();
This one returns a reference to an int. This does not affect the lifetime of that value though, so this can lead to undefined behavior in a case such as this:
int& exampleTwo() {
int x = 42;
return x;
}
we're returning a reference to a value that no longer exists. The compiler may warn you about this, but it'll probably compile anyway. But it's meaningless and will cause funky crashes sooner or later. This is used often in other cases though. If the function had been a class member, it could return a reference to a member variable, whose lifetime would last until the object goes out of scope, which means function return value is still valid when the function returns.
const int& exampleThree();
Is mostly the same as above, returning a reference to some value without taking ownership of it or affecting its lifetime. The main difference is that now you're returning a reference to a const (immutable) object. Unlike the first case, this is more often useful, since we're no longer dealing with a copy that no one else knows about, and so modifications may be visible to other parts of the code. (you may have an object that's non-const where it's defined, and a function that allows other parts of the code to get access to it as const, by returning a const reference to it.
Your first case:
const int exampleOne();
With simple types like int, this is almost never what you want, because the const is pointless. Return by value implies a copy, and you can assign to a non-const object freely:
int a = exampleOne(); // perfectly valid.
When I see this, it's usually because whoever wrote the code was trying to be const-correct, which is laudable, but didn't quite understand the implications of what they were writing. However, there are cases with overloaded operators and custom types where it can make a difference.
Some compilers (newer GCCs, Metrowerks, etc) warn on behavior like this with simple types, so it should be avoided.
I think that your question is actually two questions:
What are the implications of returning a const.
What are the implications of returning a reference.
To give you a better answer, I will explain a little more about both concepts.
Regarding the const keyword
The const keyword means that the object cannot be modified through that variable, for instance:
MyObject *o1 = new MyObject;
const MyObject *o2 = o1;
o1->set(...); // Will work and will change the instance variables.
o2->set(...); // Won't compile.
Now, the const keyword can be used in three different contexts:
Assuring the caller of a method that you won't modify the object
For example:
void func(const MyObject &o);
void func(const MyObject *o);
In both cases, any modification made to the object will remain outside the function scope, that's why using the keyword const I assure the caller that I won't be modifying it's instance variables.
Assuring the compiler that a specific method do not mutate the object
If you have a class and some methods that "gets" or "obtains" information from the instance variables without modifying them, then I should be able to use them even if the const keyword is used. For example:
class MyObject
{
...
public:
void setValue(int);
int getValue() const; // The const at the end is the key
};
void funct(const MyObject &o)
{
int val = o.getValue(); // Will compile.
a.setValue(val); // Won't compile.
}
Finally, (your case) returning a const value
This means that the returned object cannot be modified or mutated directly. For example:
const MyObject func();
void func2()
{
int val = func()->getValue(); // Will compile.
func()->setValue(val); // Won't compile.
MyObject o1 = func(); // Won't compile.
MyObject o2 = const_cast<MyObject>(func()); // Will compile.
}
More information about the const keyword: C++ Faq Lite - Const Correctness
Regarding references
Returning or receiving a reference means that the object will not be duplicated. This means that any change made to the value itself will be reflected outside the function scope. For example:
void swap(int &x, int &y)
{
int z = x;
x = y;
y = z;
}
int a = 2; b = 3;
swap(a, b); // a IS THE SAME AS x inside the swap function
So, returning a reference value means that the value can be changed, for instance:
class Foo
{
public:
...
int &val() { return m_val; }
private:
int m_val;
};
Foo f;
f.val() = 4; // Will change m_val.
More information about references: C++ Faq Lite - Reference and value semantics
Now, answering your questions
const int exampleOne();
Means the object returned cannot change through the variable. It's more useful when returning objects.
int& exampleTwo();
Means the object returned is the same as the one inside the function and any change made to that object will be reflected inside the function.
const int& exampleThree();
Means the object returned is the same as the one inside the function and cannot be modified through that variable.
Never thought, that we can return a const value by reference and I don't see the value in doing so..
But, it makes sense if you try to pass a value to a function like this
void func(const int& a);
This has the advantage of telling the compiler to not make a copy of the variable a in memory (which is done when you pass an argument by value and not by reference). The const is here in order to avoid the variable a to be modified.
E.g.
What's best out of these:
std::string f() {}
or
const std::string& f() {}
A function should never return a reference to a local object/variable since such objects go out of the scope and get destroyed when the function returns.
Differently, the function can return a const or non const reference to an object whose scope is not limited by the function context. Typical example is a custom operator<<:
std::ostream & operator<<(std::ostream &out, const object &obj)
{
out << obj.data();
return out;
}
Unfortunately, returning-by-value has its performance drawback. As Chris mentioned, returning an object by value involves the copy of a temporary object and its subsequent destruction. The copy takes place by means of either copy constructor or operator=. To avoid these inefficiencies, smart compilers may apply the RVO or the NRVO optimizations, but there are cases in which they can't -- multiple returns.
The upcoming C++0x standard, partially available in gnu gcc-4.3, introduces the rvalue reference [&&] that can be used to distinguish a lvalue from a rvalue reference. By means of that, it's possible to implement the move constructor, useful to return an object partially avoiding the cost of copy constructor and the destructor of the temporary.
The move constructor is basically what Andrei envisioned some years ago in the article http://www.ddj.com/database/184403855 suggested by Chris.
A move constructor has the following signature:
// move constructor
object(object && obj)
{}
and it's supposed to take the ownership of the internals of the passed object leaving the latter in a default state. By doing that, copies of internals are avoided and the destruction of the temporary made easy. A typical function factory will then have the following form:
object factory()
{
object obj;
return std::move(obj);
}
The std::move() returns a rvalue reference from an object. Last but not least, move constructors allow the return-by-rvalue-reference of non-copyable objects.
I would like to add to Nicola's excellent answer. Yes, you must never return a dangling reference (e.g., reference to a local variable), however, there are three useful ways to improve performance in those cases:
Return-value optimisation (RVO): You return by value, but eliminate copying by having only one return statement, which creates the return value on the spot. Here's an example of RVO being used: How can I tokenize a C++ string?
Named return-value optimisation (NRVO): You return by value, and declare the return value variable first, at the top of the function. All return statements return that variable. With compilers that support NRVO, that variable is allocated in the return-value slot, and does not get copied upon return. e.g.,
string
foobar()
{
string result;
// fill in "result"
return result;
}
Use a shared_ptr or the like as the return type; this necessitates creating your object on the heap, rather than the stack. This prevents dangling-reference problems while still not requiring the whole object to be copied, just the smart pointer.
By the way, I can't take credit for the information about RVO and NRVO; they come straight out of Scott Meyers's More Effective C++. Since I don't have the book with me at the moment, any errors in my description are my doing, not Scott's. :-)
If you return a reference to a variable that is local to the function then you're going to end up with issues (depending on the compiler and its settings).
If you return a reference to an instance that's still in scope when the function returns then it will be faster, as no copy of the string is being created.
So the latter is more efficient (technically) but may not function as expected depending on what you return a reference to.