This is a little subjective I think; I'm not sure if the opinion will be unanimous (I've seen a lot of code snippets where references are returned).
According to a comment toward this question I just asked, regarding initializing references, returning a reference can be evil because, [as I understand] it makes it easier to miss deleting it, which can lead to memory leaks.
This worries me, as I have followed examples (unless I'm imagining things) and done this in a fair few places... Have I misunderstood? Is it evil? If so, just how evil?
I feel that because of my mixed bag of pointers and references, combined with the fact that I'm new to C++, and total confusion over what to use when, my applications must be memory leak hell...
Also, I understand that using smart/shared pointers is generally accepted as the best way to avoid memory leaks.
i think using reference as the return value of the function is much more straight forward than using pointer as the return value of the function. Secondly It would be always safe to use static variable to which the return value refer to.
Addition to the accepted answer:
struct immutableint { immutableint(int i) : i_(i) {} const int& get() const { return i_; } private: int i_; };
I'd argue that this example is not okay and should be avoided if possible. Why? It is very easy to end-up with a dangling reference.
To illustrate the point with an example:
struct Foo
{
Foo(int i = 42) : boo_(i) {}
immutableint boo()
{
return boo_;
}
private:
immutableint boo_;
};
entering the danger-zone:
Foo foo;
const int& dangling = foo.boo().get(); // dangling reference!
"returning a reference is evil because, simply [as I understand] it makes it easier to miss deleting it"
Not true. Returning a reference does not imply ownership semantics. That is, just because you do this:
Value& v = thing->getTheValue();
...does not mean you now own the memory referred to by v;
However, this is horrible code:
int& getTheValue()
{
return *new int;
}
If you are doing something like this because "you don't require a pointer on that instance" then: 1) just dereference the pointer if you need a reference, and 2) you will eventually need the pointer, because you have to match a new with a delete, and you need a pointer to call delete.
Best thing is to create object and pass it as reference/pointer parameter to a function which allocates this variable.
Allocating object in function and returning it as a reference or pointer (pointer is safer however) is bad idea because of freeing memory at the end of function block.
You should return a reference to an existing object that isn't going away immediately, and where you don't intend any transfer of ownership.
Never return a reference to a local variable or some such, because it won't be there to be referenced.
You can return a reference to something independent of the function, which you don't expect the calling function to take the responsibility for deleting. This is the case for the typical operator[]
function.
If you are creating something, you should return either a value or a pointer (regular or smart). You can return a value freely, since it's going into a variable or expression in the calling function. Never return a pointer to a local variable, since it will go away.
Not only is it not evil, it is sometimes essential. For example, it would be impossible to implement the [] operator of std::vector without using a reference return value.
Class Set {
int *ptr;
int size;
public:
Set(){
size =0;
}
Set(int size) {
this->size = size;
ptr = new int [size];
}
int& getPtr(int i) {
return ptr[i]; // bad practice
}
};
getPtr function can access dynamic memory after deletion or even a null object. Which can cause Bad Access Exceptions. Instead getter and setter should be implemented and size verified before returning.
return reference is usually used in operator overloading in C++ for large Object, because returning a value need copy operation.(in perator overloading, we usually don't use pointer as return value)
But return reference may cause memory allocation problem. Because a reference to the result will be passed out of the function as a reference to the return value, the return value cannot be an automatic variable.
if you want use returning refernce, you may use a buffer of static object. for example
const max_tmp=5;
Obj& get_tmp()
{
static int buf=0;
static Obj Buf[max_tmp];
if(buf==max_tmp) buf=0;
return Buf[buf++];
}
Obj& operator+(const Obj& o1, const Obj& o1)
{
Obj& res=get_tmp();
// +operation
return res;
}
in this way, you could use returning reference safely.
But you could always use pointer instead of reference for returning value in functiong.
No. No, no, a thousand times no.
What is evil is making a reference to a dynamically allocated object and losing the original pointer. When you new
an object you assume an obligation to have a guaranteed delete
.
But have a look at, eg, operator<<
: that must return a reference, or
cout << "foo" << "bar" << "bletch" << endl ;
won't work.
It's not evil. Like many things in C++, it's good if used correctly, but there are many pitfalls you should be aware of when using it (like returning a reference to a local variable).
There are good things that can be achieved with it (like map[name] = "hello world")
Function as lvalue (aka, returning of non-const references) should be removed from C++. It's terribly unintuitive. Scott Meyers wanted a min() with this behavior.
min(a,b) = 0; // What???
which isn't really an improvement on
setmin (a, b, 0);
The latter even makes more sense.
I realize that function as lvalue is important for C++ style streams, but it's worth pointing out that C++ style streams are terrible. I'm not the only one that thinks this... as I recall Alexandrescu had a large article on how to do better, and I believe boost has also tried to create a better type safe I/O method.
I find the answers not satisfactory so I'll add my two cents.
Let's analyze the following cases:
int& getInt()
{
int x = 4;
return x;
}
This is obviously error
int& x = getInt(); // will refer to garbage
int& getInt()
{
static int x = 4;
return x;
}
This is right, because static variables are existant throughout lifetime of a program.
int& x = getInt(); // valid reference, x = 4
This is also quite common when implementing Singleton pattern
Class Singleton
{
public:
static Singleton& instance()
{
static Singleton instance;
return instance;
};
void printHello()
{
printf("Hello");
};
}
Usage:
Singleton& my_sing = Singleton::instance(); // Valid Singleton instance
my_sing.printHello(); // "Hello"
Standard library containers depend heavily upon usage of operators which return reference, for example
T & operator*();
may be used in the following
std::vector<int> x = {1, 2, 3}; // create vector with 3 elements
std::vector<int>::iterator iter = x.begin(); // iterator points to first element (1)
*iter = 2; // modify first element, x = {2, 2, 3} now
There are times when & may be used for quick access to internal data
Class Container
{
private:
std::vector<int> m_data;
public:
std::vector<int>& data()
{
return m_data;
}
}
with usage:
Container cont;
cont.data().push_back(1); // appends element to std::vector<int>
cont.data()[0] // 1
HOWEVER, this may lead to pitfall such as this:
Container* cont = new Container;
std::vector<int>& cont_data = cont->data();
cont_data.push_back(1);
delete cont; // This is bad, because we still have a dangling reference to its internal data!
cont_data[0]; // dangling reference!
I ran into a real problem where it was indeed evil. Essentially a developer returned a reference to an object in a vector. That was Bad!!!
The full details I wrote about in Janurary: http://developer-resource.blogspot.com/2009/01/pros-and-cons-of-returing-references.html
There are two cases:
const reference --good idea, sometimes, especially for heavy objects or proxy classes, compiler optimization
non-const reference --bad idea, sometimes, breaks encapsulations
Both share same issue -- can potentially point to destroyed object...
I would recommend using smart pointers for many situations where you require to return a reference/pointer.
Also, note the following:
There is a formal rule - the C++ Standard (section 13.3.3.1.4 if you are interested) states that a temporary can only be bound to a const reference - if you try to use a non-const reference the compiler must flag this as an error.
About horrible code:
int& getTheValue()
{
return *new int;
}
So, indeed, memory pointer lost after return. But if you use shared_ptr like that:
int& getTheValue()
{
std::shared_ptr<int> p(new int);
return *p->get();
}
Memory not lost after return and will be freed after assignment.
Source: Stackoverflow.com