简体   繁体   中英

Reference Operator to a Return Value?

I'm learning Objecct Oriented Programming in C++. I have some doubts about the following code:

class Vehicle 
{ 
  protected: 
    string license ; int year ;
  public:
    Vehicle(const string &myLicense, const int myYear) : license(myLicense), year(myYear){}

    const string getDesc() const 
    {
      return license + " from " + stringify(year);
    } 
    const string &getLicense() const {return license;} 
    const int getYear() const {return year;} 
};
  • what does it mean to use the reference operator (&) for the return value of a function. Why is it convenient to use? I think that the result is exactly the same and you use the same ammount of memory whether or not you use the (&) in the getlicense function.

  • why does this code use the reserved word const? I see it can work withusing using it. is there any advantage of using const in the code?

Thanks in advance for your help folks.

By returning a reference to license you save a copy operation which would incur a memory allocation. By making it a const reference it prevents callers from modifying internal state.

It is used to avoid unecessary copy when returning the object, although it depends on the call-site as well, as at the call-site one can make a copy, and may not make a copy:

std::string copy = veh.getLicence(); //makes a copy
const std::string & notAcopy = veh.getLicence(); //does not make a copy

//and most importantly here
size_t size = veh.getLicense().size(); //doesn't make a copy!

Returning a reference particularly helps in chained function calls. In chained function calls, if you do not want to call a function on a copy , then you've to return by reference, so that you can ensure that the chained function call is on the original object, just like in the third example above.

There are some classes whose return type has to be reference type (or pointer type), otherwise it wouldn't work because their copy-constructors has been disabled by declaring them private . The most frequently used such classes are IOStream classes, eg std::istream , std::ostream and all classes deriving from them. In such cases, you've to use std::ostream& as return type of a function (usually these functions are operator<< overloads).

When you have const string &getLicense() const {return license;} , it means that you return the license value by reference . Without the & you will return by value. Quoting :

When a variable is returned by reference, a reference to the variable is passed back to the caller. The caller can then use this reference to continue modifying the variable, which can be useful at times. Return by reference is also fast, which can be useful when returning structs and classes.

Now, without the const , the caller would be able to modify the value of your license member value, and according to the code you don't want this to happen.

So, to summarize, & is used in order to return by reference, which is faster than return by value (because you just return a reference and you don't copy an object), and const is used in order to forbid the modification.


You can read more about return-by-reference here, on C++-FAQ-lite .

Please format your code better! That is unnecessarily hard to parse:

class Vehicle 
{ 
public:
  Vehicle(const string & myLicense, const int myYear)
    : license(myLicense)
    , year(myYear) 
  {}

  const string getDesc() const 
  {
    return license + " from " + stringify(year);
  } 
  const string & getLicense() const {return license;} 
  const int getYear() const {return year;} 
protected:
  // good convention: put details that users shouldn't be paying attention to 
  // below the public parts that they *should* be paying attention to
  string license;
  int year;
};

Returning a const string & means you're giving read-only (const) access to the outside world to directly interact (by reference) with this object's license (because that's what getLicense() does).

Usually that's an efficiency option. ie you could return license by value (copy), but then you're copying the contents of license. This way you're simply giving direct access, but stipulating it is read-only.

const on the return indicates it's read-only nature. const on the end of a method declaration means that you're stating that this method won't alter the value of this object.

The latter is especially important if the caller has a const instance of Vehicle. The caller will not be allowed to call non-const methods, because they only have read-only access to their instance of a Vehicle.

Returning a reference can avoid a copy as others have already pointed out. I feel obliged to point out, however, that there's usually more to the story than that.

First of all, returning a reference to a local object generally leads to problems. Therefore, when you return a reference, you generally need to be doing one of two things:

  1. You're returning a reference to some pre-existing object (eg, many of the iostreams operators are passed a reference to the iostream, and return a reference to the same iostream; similarly, an assignment operator will normally return *this; ).
  2. The function dynamically allocates the object it returns. In this case, however, it's rather more common to return a pointer than a reference.

I'd go so far as to say that in most cases, the lack of copying (or at least the efficiency gained from lack of copying) involved is a more or a sideline than the primary reason you return a reference. In the case of an iostream, you're returning a reference primarily because an iostream is basically an "identity" kind of object -- ie, you can't copy or assign one. You create one, use references to that one, sole object, and when you're done you destroy it.

When you pass a reference to an object, the primary intent is often to eliminate a copy. When you return a reference, however, that's much less often the case.

I'd also note that for quite a while now most compilers have implemented Return Value Optimization and Named Return Value Optimization (RVO/NRVO). This means returning a value often won't lose any efficiency compared to returning a reference in any case (in fact, what'll happen is the compiler will internally turn your code that returns a value into code that receives a reference, and writes directly to the parent's value).

Bottom line: returning a reference isn't quite as simple or obvious as it may initially seem. Outside of the handful of situations where it's routine (insertion, extraction, and assignment operators being the most obvious) it's something you probably really need to think about and know what you're doing, not just a simple, obvious optimization.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM