views:

744

answers:

6

In a project I maintain, I see a lot of code like this for simple get/set methods

const int & MyClass::getFoo() { return m_foo; }

void MyClass::setFoo(const int & foo) { m_foo = foo; }

What is the point in doing that instead of the following?

int MyClass::getFoo() { return m_foo; }  // Removed 'const' and '&' 

void MyClass::setFoo(const int foo) { m_foo = foo; }  // Removed '&'

Passing a reference to a primitive type should require the same (or more) effort as passing the type's value itself, right?
It's just a number after all...
Is this just some attempted micro-optimization or is there a true benefit?

+4  A: 

The main difference between returning a value and returning a const reference is that you then can const_cast that reference and alter the value.

It's an example of bad design and an attempt to create a smart design where easy and concise design would be more than enough. Instead of just returning a value the author makes readers of code think what intention he might have had.

sharptooth
+9  A: 

The difference is that if you get that result into a reference yourself you can track the changes of the integer member variable in your own variable name without recalling the function.

const &int x = myObject.getFoo();
cout<<x<<endl;
//...
cout<<x<<endl;//x might have changed

It's probably not the best design choice, and it's very dangerous to return a reference (const or not), in case a variable that gets freed from scope is returned. So if you return a reference, be careful to be sure it is not a variable that goes out of scope.

There is a slight difference for the modifier too, but again probably not something that is worth doing or that was intended.

void test1(int x)
{
  cout<<x<<endl;//prints 1
}

void test2(const int &x)
{
  cout<<x<<endl;//prints 1 or something else possibly, another thread could have changed x
}

int main(int argc, char**argv)
{
  int x = 1;
  test1(x);
  //...
  test2(x);
  return 0;
}

So the end result is that you obtain changes even after the parameters are passed.

Brian R. Bondy
"it's very dangerous to return a reference (const or not)" - I'm curious, how do you then return more heavyweight values? Maybe the need do is a sign of poor design, but I tend to return strings by const ref.
Dominic Rodger
@me - I'm not saying strings are heavyweight, I just prefer to avoid the (admittedly probably minor) overhead of copying them around.
Dominic Rodger
This way you have to think about the object lifetime. That may be worth for complex datatypes, but not fro primitives which are copied at the same cost as references.
sharptooth
@sharptooth: I agree
Brian R. Bondy
@sharptooth - so returning const ref is not an inherent evil?
Dominic Rodger
@Dominic Rodger: Should be used with caution that's all.
Brian R. Bondy
@Dominic Rodger: It might be useful, but in most cases you won't use its potential for anything like what Brian described. And the problem with readability remains there anyway. You decide whether you need a likely useless mechanism that reduces readability.
sharptooth
+1  A: 

I think this type of code is written who have misunderstood the concept of references and use it for everything including primitive data types. I've also seen some code like this and can't see any benefit of doing this.

Naveen
A: 

There is no point and benefit except

void MyClass::setFoo(const int foo)
void MyClass::setFoo(const int& foo)

as then you won't be able to reuse 'foo' variable inside 'setFoo' implementation. And I believe that 'int&' is just because Guy just get used to pass all things by const reference and there is nothing wrong with that.

Mykola Golubyev
+4  A: 

There is not much benefit. I have seen this in framework or macro generated getters and setters before. The macro code did not distinguish between primitive and non-POD types and just used const type& across the board for setters. I doubt that it is an efficiency issue or a genuine misunderstanding; chances are this is a consistency issue.

D.Shawley
+1 for calling it a consistency issue.
David Thornley
+2  A: 

To me, passing a const reference for primitives is a mistake. Either you need to modify the value, and in that case you pass a non-const reference, or you just need to access the value and in that case you pass a const.

Const references should only be used for complex classes, when copying objects could be a performance problem. In the case of primitives, unless you need to modify the value of the variable you shouldn't pass a reference. The reason is that references take more computation time than non-references, since with references, the program needs to look up in a table to find the address of the object. When this look-up time is shorter than the copying time, references are an improvement.

Generally, ints and addresses have the same byte length in low-level implementations. So the time of copying an int as a return value for a function is equivalent to the time of copying an address. But in the case where an int is returned, no look up is performed, therefore performance is increased.

Manu