views:

217

answers:

7

I'm not sure what to return as a default?

myDrugs is a private vector<Drug*> container

Drug* DrugDealer::getFirstDrugInSack(DrugType drugtobuy)
{
    for (int i = 0; i < myDrugs.size(); i++)
    {
     if (myDrugs[i]->getType() == drugtobuy)
      return myDrugs[i];
    }

    return 0; // is this right?
}

So I would call it like:

Drug *d = DrugDealer->getFirstDrugInSack(DrugType::Weed);
if (d != 0)
    // do something
else
    // onose?

Or is there a better way to do this?

+1  A: 
Drug *myDrug = NULL;
In the loop, myDrug = myDrugs[i] followed by break;
and return myDrug.
Murali VP
+5  A: 

Some people prefer NULL to 0. You could also raise an exception.

Ned Batchelder
NULL is a C-ism, I'm pretty certain 0 is the preferred form for C++.
paxdiablo
I know I prefer 0, since C++ guarantees its meaning, but some people still prefer NULL.
Ned Batchelder
AFAIK NULL is #defined as 0 (at least Microsoft does it) so there's no problem. I actually prefer NULL for pointers.
mxp
You fools! `nullptr` is the one true way!
Simon Buchan
A: 

Yes, this is OK. Consider using exceptions if the case where you don't have an object doesn't occur too often, and the code handling those objects gets complex.

3yE
+13  A: 

I would say it depends on whether the function expects to find the value, and this comes down to how well-defined and cohesive your function is, and what type of contract it is providing to client code.

If it is acceptable to not find the value, I would say that returning a NULL pointer in this case is valid as a way of indicating to the client code that the value couldn't be found.

If it is an exceptional circumstance to not find a value and this indicates that there is something wrong, perhaps one of the following approaches is better:

  • Throwing an exception.
  • Asserting in conjunction with returning NULL. Asserting on its own is usually not recommended as these are (usually) compiled out of Release builds.

In your case I would say that returning NULL is acceptable, but as indicated above this changes for every situation and there is no particular "rule of thumb" to apply here.

LeopardSkinPillBoxHat
+1 for going beyond the question and explaining the important difference between NULL as an *acceptable* vs. *exceptional* result.
Bob Kaufman
+3  A: 

Returning NULL is Ok. You may also consider passing a pointer to pointer as a parameter and returning boolean value, true if it is found and false if it is not:

bool DrugDealer::getFirstDrugInSack(DrugType drugtobuy, Drug** out)
{
    for (int i = 0; i < myDrugs.size(); i++)
    {
        if (myDrugs[i]->getType() == drugtobuy) {
           *out = myDrugs[i];
           return true;
        }

    }

    return false;
}

Calling:

Drug* d;
if (dealer->getFirstDrugInSack(dragType, &d)) {
  // Found it, use it
}
Dmitry
How would I call that pointer to a pointer business? Drug *d = new Drug(); if (dealer->getFirst(d)) // do something?
Joshua
Dmitry
No, that would leak the newed Drug when getFirst() overwrites it. You can either not initialize it: `Drug* d; if (dealer->getFirst(type, `. Since you don't want to read it if it's not set, either is fine.
Simon Buchan
Ah yea I thought it would leak memory. Was confused for a second where the double pointer came in but by reference makes sense.
Joshua
Dmitry
A: 

another option you can make use of is returning a NullObject

return Drug::NullDrug;

basically a valid drug object that is considered "NUll" means that if you use it, it won't break.

though generally I'd go with returning 0;

well,

usually, I'd be using smart ptrs.

Keith Nicholas
+1  A: 

I would say you have three options:

  1. return 0
  2. throw an exception
  3. use the Null object pattern

1) Has the drawback that you have to test for 0 if you want to avoid exceptions. This is not the way to go if you write modern C++ code as it makes the code jumpy (a lot of if's) and exceptions would make the code slow if the case where 0 is returned in not that likely (then it is not really an exception ;-) )

2) Same thing, only a way to go if the situation is unlikely

3) This will make the code work in all cases, only where you have to check if there are drugs or not, you have to compare to the defined NullObject, not to 0. This could alternatively also be solved by using std::shared_ptr (which has become part of the new C++ standard lib, if you have an older STL, you can use boost::shared_ptr, it is a header only template class)

FYI: I gathered the design patterns I could find and put them into an overviewable list http://www.color-of-code.de/index.php?option=com_content&amp;view=article&amp;id=68:software-patterns&amp;catid=43:design&amp;Itemid=66 There are backlinks to wikipedia for the entries I could find.

EDIT: Here the link for the Null Object Pattern only: http://en.wikipedia.org/wiki/Null_Object_pattern

jdehaan