Sign in to follow this  

Return value

This topic is 1109 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi,

   I am trying to convert a function. Working with pointers, my function is looks like this -

The container-

std::vector<COne*> m_OneContainer;

When I have to find something, I do like this -

COne* CScene::getOneFromId(int id)
{
   for(auto &it: m_OneContainer)
   {
      if((*it)->getID() == id)
      {
         return *it;
      }
   return 0;
}

But when I work with reference -

std::vector<COne> m_OneContainer;

Function -

COne& CScene::getOneFromId(int id)
{
   for(auto &it: m_OneContainer)
   {
      if(it.getID() == id)
      {
         return it;
      }
   return 0; // What do I return here??
}

My question is what do I return as NULL?

 

Thank you

Share this post


Link to post
Share on other sites

You need to ask yourself what you expect to happen in your program. Is it expected behavior that sometimes you will not find a "one"? (In which case, return a null pointer, or do something like NLScotty suggests) Or is this like a failure condition indicating a bug in your program? (In which case, assert, or throw an exception).

 

Anyway, why do you want to convert it from pointers to objects?

Share this post


Link to post
Share on other sites

Pointers are references that can be null. References themselves can't be null*. That's one of the strengths and guarantees* of references.

 

*Normally. You can cram an address of 0x00 into a reference's memory, but you shouldn't. It defeats the point of using a reference over a pointer.

 

Some people use a wrapper class called optional<> for that. Boost has an implementation, and C++ will likely get a standard library class like that, but that's still a "maybe" and way off in 2017.

 

If your object type has some concept of being null, empty, or invalid, you can return a reference to an invalid dummy member variable for invalid returns, but I only recommend you do that if you're returning const references or returning by value.

 

For example, if the function returns strings or std vectors, you can return an empty string or vector on failure, when it makes sense. But even this isn't the best idea, because you still don't know if the function returned an empty string because of failure, or an empty string because of success.

 

What I do in this situation, is I pass in the "fallback result" as the final parameter:

const std::string &GetSomething(const std::string &key, const std::string &fallback)
{
     if(...doesn't exist...) return fallback;
 
     return stuff[key];
}

This is for cases where failing to find a result is not considered an error. If it is actually an error, you want the caller to somehow be able to be informed about that, so you should at least be able to pass in an optional boolean pointer to set to true on error.

Edited by Servant of the Lord

Share this post


Link to post
Share on other sites

 

*Normally. You can cram an address of 0x00 into a reference's memory, but you shouldn't. It defeats the point of using a reference over a pointer.

 

If you accept undefined behavior, then anything is possible. You cannot have a well defined null-reference.

Share this post


Link to post
Share on other sites

You have to dereference the iterator to get a reference to the object, and then take the address of that reference to get a pointer to the object.

return &*it;

Just taking the address of the iterator will give you a pointer to an iterator to a COne object, but that is not what the function is suppose to return.

Share this post


Link to post
Share on other sites
That's the same pointer version from before, not a reference.

If you are asking for permission, you can do it however you want. That way is functional.

The design you use depends on your actual needs. In the case you just gave you're returning a null pointer, which often works for designs but sometimes not. If your system is built so that it detects null pointers coming from the function, and everywhere you use it you always test for a null result, then it works.

If you really need a reference to an object, some designs will use a special "failure object". It is not a null pointer, instead it is a valid object with a bunch of special features. It can be useful in systems like creating a game object from an object factory in a large data-driven game. Creating a failure object in this kind of game will pull up some dialog boxes on debug builds and test builds so QA can log it, but the failure object can be gracefully used as a valid game object by all the game systems.

Share this post


Link to post
Share on other sites

Yes, you can do that - though you can just return &it too.

 

I think Brother Bob may have misread the code, "it" is not directly an iterator object. A different name can help disambiguate, e.g. "entry", "element", etc.

Share this post


Link to post
Share on other sites

I think Brother Bob may have misread the code, "it" is not directly an iterator object. A different name can help disambiguate, e.g. "entry", "element", etc.

Indeed I did. The name sure made me assume it was an iterator so I didn't even pay attention to the loop. Thanks for pointing that out.

Share this post


Link to post
Share on other sites

Hi.

 

You could define some return codes and pass out the params from the functions params and check the return code of the function.

 

Like.

DWORD Find(cOne &out, other params if needed)

{

      DWORD error = MYDEFINE_ERROR;

      if(not found)

          return error;

   return MYDEFINE_ALLOK;

}

Share this post


Link to post
Share on other sites
Sorry ankhd, but I cannot see anything positive with that.

Why would you use a Win32-only type like DWORD? Especially with the standard library offering you much better alternatives like std::uint32_t or std::uint_fast32_t. Why use something like that at all when a bool does it? Or if you actually needed more return values, why not a (strongly type) enum? Why defines?

Also, you need cOne to have an input instance here. Not everything is default constructible that easily, if it is not, where to get the input instance? cOne must also by assignable for this to work (and if it's assignable, an assign can be very expensive). Granted, both of these problems could be fixed by using a pointer instead of a reference or knowing exactly what cOne can and cannot do.

But at the end of the day I still see no advantage of this of this compared to SmkViper's use of std::find_if. Edited by BitMaster

Share this post


Link to post
Share on other sites

This topic is 1109 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this