2

I have the following piece of code which searches a map of type std::map<int, const CustomClass&>. I would like to return a "failure" case object if the item is not found in the map.

I went through the discussion in Returning a “NULL reference” in C++?

Using std::pair with a bool to indicate if the item is valid or not (note: requires that SomeResource has an appropriate default constructor and is not expensive to construct):

std::pair<SomeResource, bool> SomeClass::getSomething(std::string name) {
    std::map<std::string, SomeResource>::iterator it = content_.find(name);
    if (it != content_.end()) 
        return std::make_pair(*it, true);  
    return std::make_pair(SomeResource(), false);

}

but since my CustomClass is an Abstract Base Class I cannot instantiate it !

Are there any better ways to circumvent this ? I imagine returning a pointer to the class object might allow it to be mutable. I would like to keep the returned object immutable.

My code sample is shown below -

std::pair<const NpBaseTest::NpBaseTest&, bool> NpTestMgr::find(const UID& p_uid) const
{
    auto search = m_pending.find(p_uid);
    if(search != m_pending.end())
        return std::make_pair(*search, true);
    return std::make_pair(NpBaseTest(), false);
}
Community
  • 1
  • 1
nitimalh
  • 919
  • 10
  • 26
  • If you return a pointer to a const object, you can't modify the object pointed by the returned pointer – max66 Feb 01 '17 at 19:47

2 Answers2

2

You should just do what C++17 std::optional is doing. It doesn't require any special compiler support, so you can simply borrow the implementation from any library which supports it. For example, CLang version of libc++ is usually easy to read.

One thing you most likely do not want to do is to return the pointer. It is not the question of mutability, but rather a dynamic memory management.

SergeyA
  • 61,605
  • 5
  • 78
  • 137
  • Is it because it would be up to the user of the member function to be responsible for freeing the pointer ? or rather a user, who is not supposed to free the pointer might do so leading to double frees ? – nitimalh Feb 01 '17 at 20:02
  • @ImNot, deleting part can be solved with `unique_ptr`. But performance implications of it will remain. – SergeyA Feb 01 '17 at 20:04
  • If you dont mind, could you tell me a little bit more about what are these performance implications (or point me to a resource where I can learn about the implications of returning pointers). The reason I ask is because I would love to learn why the "best practices" are considered the best. – nitimalh Feb 01 '17 at 20:09
  • `std::optional` does not work with polymorphic types (see also [this question](http://stackoverflow.com/questions/37369429/stdoptional-and-polymorphism)). – G. Sliepen Feb 01 '17 at 20:15
  • @ImNot, operations such as `new` and `delete` are somewhat slow, can result in system calls and are a major penalty in multithreaded apps – SergeyA Feb 01 '17 at 20:23
  • @G.Sliepen, well, returning polymorphic types by value is never a good idea. But since OP is eager to do this for cases when object was found, I assume, `std::optional` would be no worse. – SergeyA Feb 01 '17 at 20:26
  • So how should polymorphic types be returned ? – nitimalh Feb 01 '17 at 20:33
  • @ImNot, what's the type of `_content` and `m_pending`? – SergeyA Feb 01 '17 at 20:40
  • @SergeyA: but the question is about returning a reference to an object, not by value. And even if you wanted to return by value, you *cannot* do that with `std::optional`. – G. Sliepen Feb 01 '17 at 21:05
  • @G.Sliepen, I totally missed the fact that the pair is of the reference! Than it is simply not going to work. – SergeyA Feb 01 '17 at 21:30
1

There are several options:

  • You can indeed return a pointer. To ensure it is non-mutable, just return a const pointer.

  • You can create a special class that inherits from the base class that does nothing but signal that a value has not been found. For example:

    class NpNotFound: NpBaseTest {
        // implement pure virtual functions with dummy ones
    };
    

    And then in NpTestMgr::find() do:

    return std::make_pair(NpNotFound(), false);
    
  • Instead of returning a std::pair<SomeClass&, bool>, just return SomeClass&, and throw an exception if the value could not be found. Use this option only if it is unlikely that you are searching for something that does not exist in the map.

G. Sliepen
  • 7,637
  • 1
  • 15
  • 31