5

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?

bob.sacamento
  • 6,283
  • 10
  • 56
  • 115
  • 4
    Are you sure when you see `double operator() (const int n)` you are not actually seeing `double operator() (const int n) cont`? – NathanOliver Apr 28 '16 at 15:29
  • In a few words: the first one supports writing; the second one is available if the object is const. – E_net4 Apr 28 '16 at 15:30
  • Possible duplicate of [What are the differences between a pointer variable and a reference variable in C++?](http://stackoverflow.com/questions/57483/what-are-the-differences-between-a-pointer-variable-and-a-reference-variable-in) – piyushj Apr 28 '16 at 15:37
  • 2
    The biggest issue with this code is that it won't even compile (at least not on a C++11 rig). Function overloads cannot differ exclusively by return type. Jam a `const` after the second overload and you may have something here (and also a hint as to where each is useful). – WhozCraig Apr 28 '16 at 15:37
  • 1
    Your question seems has nothing to do with the differences between pointer and reference. – songyuanyao Apr 28 '16 at 15:38
  • 1
    Should we assume the *real code* looks something [like **this**](http://pastebin.com/jVBYKBta) ? – WhozCraig Apr 28 '16 at 15:47
  • @NathanOliver Yep, you're right. Made the change. Same note to WhozCraig too. – bob.sacamento Apr 28 '16 at 17:10

4 Answers4

6

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;
marcinj
  • 48,511
  • 9
  • 79
  • 100
4

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.

IceFire
  • 4,016
  • 2
  • 31
  • 51
4

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.

Jeremy Friesner
  • 70,199
  • 15
  • 131
  • 234
2

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.

Davit Tevanian
  • 861
  • 8
  • 16