I'm frequently run into a situation where I need to report in some way that a finding an item has failed. Since there are many ways how to deal with such a situation I'm always unsure how to do it. Here are a few examples:
class ItemCollection
{
public:
// Return size of collection if not found.
size_t getIndex(Item * inItem)
{
size_t idx = 0;
for (; idx != mItems.size(); ++idx)
{
if (inItem == mItems[idx])
{
return idx;
}
}
return idx;
}
// Use signed int and return -1 if not found.
int getIndexV2(Item * inItem)
{
for (int idx = 0; idx != mItems.size(); ++idx)
{
if (inItem == mItems[idx])
{
return idx;
}
}
return -1;
}
// Throw exception if not found.
size_t getIndexV3(Item * inItem)
{
for (size_t idx = 0; idx != mItems.size(); ++idx)
{
if (inItem == mItems[idx])
{
return idx;
}
}
throw std::runtime_error("Item not found");
}
// Store result in output parameter and return boolean to indicate success.
bool getIndex(Item * inItem, size_t & outIndex)
{
for (size_t idx = 0; idx != mItems.size(); ++idx)
{
if (inItem == mItems[idx])
{
outIndex = idx;
return true;
}
}
return false;
}
private:
std::vector<Item*> mItems;
};
I've used all of these at some point in my (young) programming carreer. I mostly use the "return size of collection" approach because it is similar to how STL iterators work. However, I'd like to make more educated choices in the future. So, on what design principles should the decision on how to deal with not-found errors be based?