As far as I can tell, there's no reason I shouldn't be allowed to pass a reference to a pointer in C++. However, my attempts to do so are failing, and I have no idea why.
This is what I'm doing:
void myfunc(string*& val)
{
// Do stuff to the string pointer
}
// sometime later
{
// ...
string s;
myfunc(&s);
// ...
}
And I'm getting this error:
cannot convert parameter 1 from 'std::string *' to 'std::string *&'
Your function expects a reference to an actual string pointer in the calling scope, not an anonymous string pointer. Thus:
string s;
string* _s = &s;
myfunc(_s);
should compile just fine.
However, this is only useful if you intend to modify the pointer you pass to the function. If you intend to modify the string itself you should use a reference to the string as Sake suggested. With that in mind it should be more obvious why the compiler complains about you original code. In your code the pointer is created 'on the fly', modifying that pointer would have no consequence and that is not what is intended. The idea of a reference (vs. a pointer) is that a reference always points to an actual object.
The problem is that you're trying to bind a temporary to the reference, which C++ doesn't allow unless the reference is const.
So you can do one of either the following:
void myfunc(string*& val)
{
// Do stuff to the string pointer
}
void myfunc2(string* const& val)
{
// Do stuff to the string pointer
}
int main()
// sometime later
{
// ...
string s;
string* ps = &s;
myfunc( ps); // OK because ps is not a temporary
myfunc2( &s); // OK because the parameter is a const&
// ...
return 0;
}
Change it to:
std::string s;
std::string* pS = &s;
myfunc(pS);
EDIT:
This is called ref-to-pointer and you cannot pass temporary address as a reference to function. ( unless it is const reference).
Though, I have shown std::string* pS = &s; (pointer to a local variable), its typical usage would be :
when you want the callee to change the pointer itself, not the object to which it points. For example, a function that allocates memory and assigns the address of the memory block it allocated to its argument must take a reference to a pointer, or a pointer to pointer:
void myfunc(string*& val)
{
//val is valid even after function call
val = new std::string("Test");
}
&s produces temporary pointer to string and you can't make reference to temporary object.
Try:
void myfunc(string& val)
{
// Do stuff to the string pointer
}
// sometime later
{
// ...
string s;
myfunc(s);
// ...
}
or
void myfunc(string* val)
{
// Do stuff to the string pointer
}
// sometime later
{
// ...
string s;
myfunc(&s);
// ...
}
EDIT: I experimented some, and discovered thing are a bit subtler than I thought. Here's what I now think is an accurate answer.
&s is not an lvalue so you cannot create a reference to it unless the type of the reference is reference to const. So for example, you cannot do
string * &r = &s;
but you can do
string * const &r = &s;
If you put a similar declaration in the function header, it will work.
void myfunc(string * const &a) { ... }
There is another issue, namely, temporaries. The rule is that you can get a reference to a temporary only if it is const. So in this case one might argue that &s is a temporary, and so must be declared const in the function prototype. From a practical point of view it makes no difference in this case. (It's either an rvalue or a temporary. Either way, the same rule applies.) However, strictly speaking, I think it is not a temporary but an rvalue. I wonder if there is a way to distinguish between the two. (Perhaps it is simply defined that all temporaries are rvalues, and all non-lvalues are temporaries. I'm not an expert on the standard.)
That being said, your problem is probably at a higher level. Why do you want a reference to the address of s? If you want a reference to a pointer to s, you need to define a pointer as in
string *p = &s;
myfunc(p);
If you want a reference to s or a pointer to s, do the straightforward thing.
Welcome to C++11 and rvalue references:
#include <cassert>
#include <string>
using std::string;
void myfunc(string*&& val)
{
assert(&val);
assert(val);
assert(val->c_str());
// Do stuff to the string pointer
}
// sometime later
int main () {
// ...
string s;
myfunc(&s);
// ...
}
Now you have access to the value of the pointer (referred to by val), which is the address of the string.
You can modify the pointer, and no one will care. That is one aspect of what an rvalue is in the first place.
Be careful: The value of the pointer is only valid until myfunc() returns. At last, its a temporary.
I have just made use of a reference to a pointer to make all the pointers in a deleted binary tree except the root safe. To make the pointer safe we just have to set it to 0. I could not make the function that deletes the tree (keeping only the root) to accept a ref to a pointer since I am using the root (this pointer) as the first input to traverse left and right.
void BinTree::safe_tree(BinTree * &vertex ) {
if ( vertex!=0 ) { // base case
safe_tree(vertex->left); // left subtree.
safe_tree(vertex->right); // right subtree.
// delete vertex; // using this delete causes an error, since they were deleted on the fly using inorder_LVR. If inorder_LVR does not perform delete to the nodes, then, use delete vertex;
vertex=0; // making a safe pointer
}
} // end in
Bottom line, a reference to a pointer is invalid when the formal parameter is the (this) pointer.
I know that it's posible to pass references of pointers, I did it last week, but I can't remember what the syntax was, as your code looks correct to my brain right now. However another option is to use pointers of pointers:
Myfunc(String** s)
myfunc("string*& val") this itself doesn't make any sense. "string*& val" implies "string val",* and & cancels each other. Finally one can not pas string variable to a function("string val"). Only basic data types can be passed to a function, for other data types need to pass as pointer or reference.
You can have either string& val or string* val to a function.
Related
I was reading some code online and I found them passing node*& instead of just node* and I didn't really understand why.
My understanding was that you pass parameters by reference when you either want your changes to sort of propagate back to the original variable outside of the function (which a pointer would do) or if you wanted to avoid copying the object every time the function is called to avoid the copying overhead which is also what a pointer would do.
Am I wrong or are they? If I am, what am I getting wrong?
When you pass by reference, it acts as an alias -- be it a normal object or a pointer.
To explain in detail, let's consider below declaration:
int i = 10, *pi = &i;
Now following are the different meanings of passing and using them in various functions:
void foo_pointer (int* p) // 1st (can pass `&i` and `pi`)
{
*p = 0; // modifies `i`
p = nullptr; // no effect on `pi`
}
void foo_pointer_reference (int*& p) // 2nd (can pass `pi`)
{
*p = 0; // modifies `i`
p = nullptr; // modifies `pi`
}
void foo_const_pointer_reference (const int*& p) // 3rd (can pass `pi`)
{
*p = 0; // ERROR
p = nullptr; // modifies `pi`
}
void foo_const_pointer_const_reference (const int* const& p) // 4th (can pass `&i` and `pi`)
{
*p = 0; // ERROR
p = nullptr; // ERROR
}
From above examples, you can see that another use case of declaring T*& as a function parameter is that, it restricts only pointer passing to that function. i.e. in above case &i is not allowed to be passed to 2nd and 3rd functions. However pi can be passed to all the functions.
You can pass a pointer by reference if you want the function you call to change the pointer to point to something else.
Other than that, I don't see any valid reason (but that is sometimes a valid reason).
I am new to C++ programming, but I have experience in Java. I need guidance on how to pass objects to functions in C++.
Do I need to pass pointers, references, or non-pointer and non-reference values? I remember in Java there are no such issues since we pass just the variable that holds reference to the objects.
It would be great if you could also explain where to use each of those options.
Rules of thumb for C++11:
Pass by value, except when
you do not need ownership of the object and a simple alias will do, in which case you pass by const reference,
you must mutate the object, in which case, use pass by a non-const lvalue reference,
you pass objects of derived classes as base classes, in which case you need to pass by reference. (Use the previous rules to determine whether to pass by const reference or not.)
Passing by pointer is virtually never advised. Optional parameters are best expressed as a std::optional (boost::optional for older std libs), and aliasing is done fine by reference.
C++11's move semantics make passing and returning by value much more attractive even for complex objects.
Rules of thumb for C++03:
Pass arguments by const reference, except when
they are to be changed inside the function and such changes should be reflected outside, in which case you pass by non-const reference
the function should be callable without any argument, in which case you pass by pointer, so that users can pass NULL/0/nullptr instead; apply the previous rule to determine whether you should pass by a pointer to a const argument
they are of built-in types, which can be passed by copy
they are to be changed inside the function and such changes should not be reflected outside, in which case you can pass by copy (an alternative would be to pass according to the previous rules and make a copy inside of the function)
(here, "pass by value" is called "pass by copy", because passing by value always creates a copy in C++03)
There's more to this, but these few beginner's rules will get you quite far.
There are some differences in calling conventions in C++ and Java. In C++ there are technically speaking only two conventions: pass-by-value and pass-by-reference, with some literature including a third pass-by-pointer convention (that is actually pass-by-value of a pointer type). On top of that, you can add const-ness to the type of the argument, enhancing the semantics.
Pass by reference
Passing by reference means that the function will conceptually receive your object instance and not a copy of it. The reference is conceptually an alias to the object that was used in the calling context, and cannot be null. All operations performed inside the function apply to the object outside the function. This convention is not available in Java or C.
Pass by value (and pass-by-pointer)
The compiler will generate a copy of the object in the calling context and use that copy inside the function. All operations performed inside the function are done to the copy, not the external element. This is the convention for primitive types in Java.
An special version of it is passing a pointer (address-of the object) into a function. The function receives the pointer, and any and all operations applied to the pointer itself are applied to the copy (pointer), on the other hand, operations applied to the dereferenced pointer will apply to the object instance at that memory location, so the function can have side effects. The effect of using pass-by-value of a pointer to the object will allow the internal function to modify external values, as with pass-by-reference and will also allow for optional values (pass a null pointer).
This is the convention used in C when a function needs to modify an external variable, and the convention used in Java with reference types: the reference is copied, but the referred object is the same: changes to the reference/pointer are not visible outside the function, but changes to the pointed memory are.
Adding const to the equation
In C++ you can assign constant-ness to objects when defining variables, pointers and references at different levels. You can declare a variable to be constant, you can declare a reference to a constant instance, and you can define all pointers to constant objects, constant pointers to mutable objects and constant pointers to constant elements. Conversely in Java you can only define one level of constant-ness (final keyword): that of the variable (instance for primitive types, reference for reference types), but you cannot define a reference to an immutable element (unless the class itself is immutable).
This is extensively used in C++ calling conventions. When the objects are small you can pass the object by value. The compiler will generate a copy, but that copy is not an expensive operation. For any other type, if the function will not change the object, you can pass a reference to a constant instance (usually called constant reference) of the type. This will not copy the object, but pass it into the function. But at the same time the compiler will guarantee that the object is not changed inside the function.
Rules of thumb
This are some basic rules to follow:
Prefer pass-by-value for primitive types
Prefer pass-by-reference with references to constant for other types
If the function needs to modify the argument use pass-by-reference
If the argument is optional, use pass-by-pointer (to constant if the optional value should not be modified)
There are other small deviations from these rules, the first of which is handling ownership of an object. When an object is dynamically allocated with new, it must be deallocated with delete (or the [] versions thereof). The object or function that is responsible for the destruction of the object is considered the owner of the resource. When a dynamically allocated object is created in a piece of code, but the ownership is transfered to a different element it is usually done with pass-by-pointer semantics, or if possible with smart pointers.
Side note
It is important to insist in the importance of the difference between C++ and Java references. In C++ references are conceptually the instance of the object, not an accessor to it. The simplest example is implementing a swap function:
// C++
class Type; // defined somewhere before, with the appropriate operations
void swap( Type & a, Type & b ) {
Type tmp = a;
a = b;
b = tmp;
}
int main() {
Type a, b;
Type old_a = a, old_b = b;
swap( a, b );
assert( a == old_b );
assert( b == old_a );
}
The swap function above changes both its arguments through the use of references. The closest code in Java:
public class C {
// ...
public static void swap( C a, C b ) {
C tmp = a;
a = b;
b = tmp;
}
public static void main( String args[] ) {
C a = new C();
C b = new C();
C old_a = a;
C old_b = b;
swap( a, b );
// a and b remain unchanged a==old_a, and b==old_b
}
}
The Java version of the code will modify the copies of the references internally, but will not modify the actual objects externally. Java references are C pointers without pointer arithmetic that get passed by value into functions.
There are several cases to consider.
Parameter modified ("out" and "in/out" parameters)
void modifies(T ¶m);
// vs
void modifies(T *param);
This case is mostly about style: do you want the code to look like call(obj) or call(&obj)? However, there are two points where the difference matters: the optional case, below, and you want to use a reference when overloading operators.
...and optional
void modifies(T *param=0); // default value optional, too
// vs
void modifies();
void modifies(T ¶m);
Parameter not modified
void uses(T const ¶m);
// vs
void uses(T param);
This is the interesting case. The rule of thumb is "cheap to copy" types are passed by value — these are generally small types (but not always) — while others are passed by const ref. However, if you need to make a copy within your function regardless, you should pass by value. (Yes, this exposes a bit of implementation detail. C'est le C++.)
...and optional
void uses(T const *param=0); // default value optional, too
// vs
void uses();
void uses(T const ¶m); // or optional(T param)
There's the least difference here between all situations, so choose whichever makes your life easiest.
Const by value is an implementation detail
void f(T);
void f(T const);
These declarations are actually the exact same function! When passing by value, const is purely an implementation detail. Try it out:
void f(int);
void f(int const) { /* implements above function, not an overload */ }
typedef void NC(int); // typedefing function types
typedef void C(int const);
NC *nc = &f; // nc is a function pointer
C *c = nc; // C and NC are identical types
Pass by value:
void func (vector v)
Pass variables by value when the function needs complete isolation from the environment i.e. to prevent the function from modifying the original variable as well as to prevent other threads from modifying its value while the function is being executed.
The downside is the CPU cycles and extra memory spent to copy the object.
Pass by const reference:
void func (const vector& v);
This form emulates pass-by-value behavior while removing the copying overhead. The function gets read access to the original object, but cannot modify its value.
The downside is thread safety: any change made to the original object by another thread will show up inside the function while it's still executing.
Pass by non-const reference:
void func (vector& v)
Use this when the function has to write back some value to the variable, which will ultimately get used by the caller.
Just like the const reference case, this is not thread-safe.
Pass by const pointer:
void func (const vector* vp);
Functionally same as pass by const-reference except for the different syntax, plus the fact that the calling function can pass NULL pointer to indicate it has no valid data to pass.
Not thread-safe.
Pass by non-const pointer:
void func (vector* vp);
Similar to non-const reference. The caller typically sets the variable to NULL when the function is not supposed to write back a value. This convention is seen in many glibc APIs. Example:
void func (string* str, /* ... */) {
if (str != NULL) {
*str = some_value; // assign to *str only if it's non-null
}
}
Just like all pass by reference/pointer, not thread-safe.
Since no one mentioned I am adding on it, When you pass a object to a function in c++ the default copy constructor of the object is called if you dont have one which creates a clone of the object and then pass it to the method, so when you change the object values that will reflect on the copy of the object instead of the original object, that is the problem in c++, So if you make all the class attributes to be pointers, then the copy constructors will copy the addresses of the pointer attributes , so when the method invocations on the object which manipulates the values stored in pointer attributes addresses, the changes also reflect in the original object which is passed as a parameter, so this can behave same a Java but dont forget that all your class attributes must be pointers, also you should change the values of pointers, will be much clear with code explanation.
Class CPlusPlusJavaFunctionality {
public:
CPlusPlusJavaFunctionality(){
attribute = new int;
*attribute = value;
}
void setValue(int value){
*attribute = value;
}
void getValue(){
return *attribute;
}
~ CPlusPlusJavaFuncitonality(){
delete(attribute);
}
private:
int *attribute;
}
void changeObjectAttribute(CPlusPlusJavaFunctionality obj, int value){
int* prt = obj.attribute;
*ptr = value;
}
int main(){
CPlusPlusJavaFunctionality obj;
obj.setValue(10);
cout<< obj.getValue(); //output: 10
changeObjectAttribute(obj, 15);
cout<< obj.getValue(); //output: 15
}
But this is not good idea as you will be ending up writing lot of code involving with pointers, which are prone for memory leaks and do not forget to call destructors. And to avoid this c++ have copy constructors where you will create new memory when the objects containing pointers are passed to function arguments which will stop manipulating other objects data, Java does pass by value and value is reference, so it do not require copy constructors.
Do I need to pass pointers, references, or non-pointer and non-reference values?
This is a question that matters when writing a function and choosing the types of the parameters it takes. That choice will affect how the function is called and it depends on a few things.
The simplest option is to pass objects by value. This basically creates a copy of the object in the function, which has many advantages. But sometimes copying is costly, in which case a constant reference, const&, is usually best. And sometimes you need your object to be changed by the function. Then a non-constant reference, &, is needed.
For guidance on the choice of parameter types, see the Functions section of the C++ Core Guidelines, starting with F.15. As a general rule, try to avoid raw pointers, *.
There are three methods of passing an object to a function as a parameter:
Pass by reference
pass by value
adding constant in parameter
Go through the following example:
class Sample
{
public:
int *ptr;
int mVar;
Sample(int i)
{
mVar = 4;
ptr = new int(i);
}
~Sample()
{
delete ptr;
}
void PrintVal()
{
cout << "The value of the pointer is " << *ptr << endl
<< "The value of the variable is " << mVar;
}
};
void SomeFunc(Sample x)
{
cout << "Say i am in someFunc " << endl;
}
int main()
{
Sample s1= 10;
SomeFunc(s1);
s1.PrintVal();
char ch;
cin >> ch;
}
Output:
Say i am in someFunc
The value of the pointer is -17891602
The value of the variable is 4
The following are the ways to pass a arguments/parameters to function in C++.
1. by value.
// passing parameters by value . . .
void foo(int x)
{
x = 6;
}
2. by reference.
// passing parameters by reference . . .
void foo(const int &x) // x is a const reference
{
x = 6;
}
// passing parameters by const reference . . .
void foo(const int &x) // x is a const reference
{
x = 6; // compile error: a const reference cannot have its value changed!
}
3. by object.
class abc
{
display()
{
cout<<"Class abc";
}
}
// pass object by value
void show(abc S)
{
cout<<S.display();
}
// pass object by reference
void show(abc& S)
{
cout<<S.display();
}
Consider function f
void f(const std::string& s) {
...
}
Is it safe to call f with a fixed string like the following:
f("abc");
The lifetime of the std::string implicitly constructed from "abc" is until the call to f() ends. So long as you aren't keeping that reference around somewhere else after f() ends, it is perfectly safe.
std::string const *pstr;
void f(std::string const &s)
{
s.length(); // safe. s has an instance backing
// it for the lifetime of this function.
pstr = &s; // still technically safe, but only if you don't
// dereference pstr after this function completes.
}
f("abc");
pstr->length(); // undefined behavior, the instance
// pstr pointed to no longer exists.
Assuming you don't store a reference or a pointer to the argument somewhere and hope that it is still around once you returned from the function, it should be OK: when the function is called, a temporary std::string is created which is around for the time the function is executed.
It's safe if you don't use it after the function returns.
Because of this, it's also safe to use it to initialize another string object (before the function returns), even if this string object lives longer (and is used longer).
Have a look at the following code. The goal here is to return a reference through two functions (from ReferenceProvider::getReference() to getRef() to main()):
#include <tchar.h>
#include <assert.h>
#include <string>
class BaseClass {
public:
virtual void write() const {
printf("In base class\n");
}
};
typedef BaseClass* BaseClassPointer;
class ChildClass : public BaseClass {
public:
virtual void write() const {
printf("In child class\n");
}
};
typedef ChildClass* ChildClassPointer;
//////////////////////////////////////////////////////////////////////////
ChildClass* g_somePointer = new ChildClass();
class ReferenceProvider {
public:
const BaseClassPointer& getReference() {
const BaseClassPointer& val = g_somePointer;
return val;
}
};
ReferenceProvider g_provider;
const BaseClassPointer& getRef() {
std::string test;
const BaseClassPointer& val = g_provider.getReference();
return val;
}
int _tmain(int argc, _TCHAR* argv[]) {
BaseClass* child = getRef();
assert(child == g_somePointer);
child->write();
return 0;
}
Now, when debugging this code (in Visual C++), breaking at return val; in getRef() will give you a screen like this:
Notice how the values of g_somePointer and val are the same. Now, step over the return statement and you'll get a screen like this:
Notice how val has become invalid (0xcccccccc). This is probably because the stack of getRef() has been cleared and val is no longer available.
The problem now is that child in _tmain() will get this invalid value (0xcccccccc) rendering child unusable. So my first (and main) question is: How to do this correctly?
(Please note that this is just an boiled down example from some other code I've been working on. It needs to be structured like with, including using references to pointers.)
What's making this whole thing very strange (and hard to debug) is that the function getRef() works under some conditions:
If you change the type of g_somePointer to BaseClass* (from ChildClass*)
If you remove the local variable in getRef() (i.e. the line std::string test;)
In both cases the reference variable val (in getRef()) will not become invalid and the function will return the correct pointer address. Can anybody explain this to me?
The problem is here:
const BaseClassPointer& val = g_somePointer;
Since g_somePointer has a different type (ChildClass* is convertible to BaseClass*, but is not the same type), val cannot refer directly to g_somePointer. Instead, a temporary copy is made, converted to the correct type, and val refers to that.
The temporary only lasts as long as val, going out of scope at the end of the function, so the function returns an invalid reference.
If you change the type of g_somePointer to BaseClass* (from ChildClass*)
In that case, no pointer conversion is required, and so val can refer directly to g_somePointer. The code is then correct, but fragile.
If you remove the local variable in getRef() (i.e. the line std::string test;)
With the string variable, there is a destructor call at the end of the function, which overwrites the defunct stack frame that contains the temporary pointer. Without it, nothing overwrites the memory, so the code appears to work - which is unfortunate, as it makes the error much harder to notice.
You can never return a reference to a local object: it will always go out of scope when the function is exited. Sometimes it may appear as if it works but this is just because the data is normally not change when the stack pointer is adjusted.
To explain what's going on:
const BaseClassPointer& val = g_somePointer;
This line is the problem. Let's do away with the typedef:
BaseClass* const& val = g_somePointer;
Here, the type of g_somePointer is ChildClass*. In order to assign it to a BaseClass*, a conversion is needed. From that conversion, a temporary pointer is introduced. That pointer is bound to a reference-to-const, which extends the temporaries lifetime until the reference dies, which is exactly the case after your return val; statement. At that point, the temporary base-class pointer doesn't exist anymore and you have undefined behaviour.
To avoid all that mess, just return a BaseClass*.
You don't want to do something like that. Returning a reference to local memory is the same as returning the address of local memory, which is undefined behavior. All sorts of things can go wrong (or by chance, things can go right).
If you want the "val" to "survive", getReference() method should return a reference to a static object. Is that "static" going to work in your current architecture is another question.
You're returning a const reference to the local val instead of the returned getRef().
Also, how do you transform the pointer to a reference?
const BaseClassPointer& val = g_somePointer;
return val;
won't work if g_somePointer is a pointer - did you use *g_somePointer or similar?
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.