2

Having read this:

Is the practice of returning a C++ reference variable, evil?

and a few other resources on references, I was wondering if something like this is OK or should I be returning a pointer?

#include <iostream>

class engine
{
public:
  int cc;
};


class car
{
protected:
  engine eng;

public:
  car (void) : eng()
  {
    eng.cc = 500;
  }

  const engine& get_engine(void) const
  {
    return eng;
  }
};


int main (void)
{
  car c = car();

  engine en = c.get_engine();


  std::cout << en.cc << std::endl;
}

Also:

What would be the difference if I changed the line

engine en = c.get_engine();

to

engine& en = c.get_engine();

both compile and give the same output but are there any subtle/not-so-subtle differences?

EDIT: as Vlad from Moscow pointed out, that last one should be const engine& en = c.get_engine();.

Community
  • 1
  • 1
jayjay
  • 1,017
  • 1
  • 11
  • 23
  • `engine& en = c.get_engine(); ` will result in a compiler error. – R Sahu May 05 '14 at 19:22
  • Using a `const&` returned from the getter is perfectly fine IMHO. The usage of non const references returned might be considered for container class access operations. – πάντα ῥεῖ May 05 '14 at 19:23
  • if your fellow engineers understand and can apply the concept and non-owning references then knock yourself out. – Captain Obvlious May 05 '14 at 19:26
  • Returning references in general isn't really evil. You should note that the evil things that were done in the question you linked were: 1. returning a reference to an object that will go out of scope and not exist anymore. 2. returning a reference to an dynamically allocated object and expecting the caller to know that he has to delete it. – AliciaBytes May 05 '14 at 19:34

3 Answers3

4

The answer depends on what you are trying to model:

  • If an engine cannot exist outside the context of its car, and if a car cannot exist without an engine, returning a reference is fine - This means that the car is going to exist at the time when you work with its engine.
  • If an engine can exist outside the context of its car, you would be better off returning a pointer (preferably, a smart pointer). This way deleting the corresponding car is not going to delete the engine.
  • Same goes if a car can exist without an engine: you need to return a pointer, because there is no such thing as null reference (hacks do not count here)

Of course these are only models of the reality - in reality, both cars without engines and engines without cars do exist. You can even swap engines between cars if they fit. However, modeling the reality to this level takes more effort on your part, so you need to make a decision on how far your model goes.

The difference between engine en = c.get_engine(); and engine &en = c.get_engine(); is that the first expression makes a copy of c's engine, while the second one references the engine in place. Among other things, this means that manipulations on the copy of the engine are not automatically reflected in the original, because they are not the same object. Another consequence is that a copy survives deletion of the car, while a reference does not.

Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
3

The difference is that in the second case the copy constructor will not be called.

Only you need to write

const engine& en = c.get_engine();

Your code is O'k.

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
  • right so in the first case: `engine en = c.get_engine();` there is no advantage over just returning the object? i.e. there is a copy operation on the entire object. – jayjay May 05 '14 at 19:27
  • @jayjay In the first example you create a new object of type engine that is a copy of the original subobject of class car. You may change this new object. In the second case you may not change the object because it is a constant reference. – Vlad from Moscow May 05 '14 at 19:29
1

From the SO post you referenced, the example given was:

int& getInt(void)
{
    int i;
    return i;
}

That is definitely not good. You are returning a reference to an object which will be gone when you return from the function.

In your case,

const engine& get_engine(void) const
{
  return eng;
}

That is a perfectly valid use of returning references to objects.

Use of

engine& en = c.get_engine();

must result in a compiler error.

R Sahu
  • 204,454
  • 14
  • 159
  • 270