Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to return a const reference which is not available

Tags:

Say I have the following function:

const std::string& Cat::getKittenName() const {   Kitten* kitty = getKitty();   return kitty->getName(); } 

Where Kitten::getName returns a const std::string& how do I best handle the case where kitty is a nullptr? I could return std::string("") but then I am returning a reference to a temporary and practically guaranteeing undefined behaviour. I could change the getKittenName function to return a std::string to get around this but then I am introducing a redundant copy for all the cases where kitty is available. Right now I feel the best option is:

const std::string& Cat::getKittenName() const {   Kitten* kitty = getKitty();   if (kitty)   {     return kitty->getName();   }   static std::string empty("");   return empty; } 

The only issue might be if 'magic statics' aren't available. Is there any problem with this solution or is there a better way to do it?

like image 683
sjdowling Avatar asked May 06 '15 09:05

sjdowling


People also ask

How do I return references to const?

You want to return a const reference when you return a property of an object, that you want not to be modified out-side of it. For example: when your object has a name, you can make following method const std::string& get_name(){ return name; }; . Which is most optimal way.

Can a const function return a non-const reference?

If the thing you are returning by reference is logically part of your this object, independent of whether it is physically embedded within your this object, then a const method needs to return by const reference or by value, but not by non-const reference.

Can you copy a const reference?

Not just a copy; it is also a const copy. So you cannot modify it, invoke any non-const members from it, or pass it as a non-const parameter to any function. If you want a modifiable copy, lose the const decl on protos .

Can a const reference refer to a non-const object?

No. A reference is simply an alias for an existing object.


2 Answers

You have several options, really.

  • The simplest one would be to return std::string, but you mentioned you do not want that for performance reasons. I'd say you should first profile to make sure it will present a noticeable performance problem, because all other solutions will make the code more complicated and hence at least a little bit harder to maintain. But let's say it does appear to be significant.

  • If you're worried about thread-safe function-scope statics not being implemented, you can create the fallback value as a static member of Cat:

    class Cat {   static const std::string missingKittenName;  public:   const std::string& Cat::getKittenName() const   {     Kitten* kitty = getKitty();     if (kitty)       return kitty->getName();     else       return missingKittenName;   } }; 
  • Since Kitten::getName() apparently returns a reference (otherwise you wouldn't be worried about copies), you could also return a pointer:

    const std::string* Cat::getKittenName() const {   Kitten* kitty = getKitty();   if (kitty)     return &kitty->getName();   else     return nullptr; } 
  • You could return an optional reference to a string:

    boost::optional<const std::string&> Cat::getKittenName() const {   Kitten* kitty = getKitty();   if (kitty)     return kitty->getName();   else     return boost::none; } 

    Since C++17, optional is part of the standard library as std::optional, so there is no longer need to fall back on Boost.

  • If the fact that a name is missing is an exception circumstance (an error), you could throw an exception:

    const std::string& Cat::getKittenName() const {   Kitten* kitty = getKitty();   if (kitty)     return kitty->getName();   else     throw std::invalid_argument("Missing kitten"); } 
like image 58
Angew is no longer proud of SO Avatar answered Sep 21 '22 04:09

Angew is no longer proud of SO


Return a reference to a const static std::string.

Reasons:

  • 'magic statics' are not magic, they are part of the c++ standard.
  • statics are constructed the first time the code flows over them (i.e. once ever)
  • as of c++11 static construction is thread safe.
  • static objects are correctly deallocated in the correct order at the end of the program
  • the performance penalty of one redundant static object is utterly negligible, and a great deal less than the cost of testing returned pointers for null.

If you're multi-threaded on a pre-c++11 compiler, then you will need to write a thread-safe singleton to manufacture the default string, or define it at file scope.

c++11:

const std::string& Cat::getKittenName() const {   static const std::string noname { /* empty string */ };   Kitten* kitty = getKitty();   if (kitty)   {     return kitty->getName();   }   return noname; } 

c++03:

namespace {     const std::string noname; }  const std::string& Cat::getKittenName() const {   Kitten* kitty = getKitty();   if (kitty)   {     return kitty->getName();   }   return noname; } 
like image 30
Richard Hodges Avatar answered Sep 21 '22 04:09

Richard Hodges