45 lines
1.5 KiB
Markdown
45 lines
1.5 KiB
Markdown
# Straight-line code: Correct usage of exceptions:
|
|
|
|
Using exceptions correctly depends on distinguishing control flow from errors.
|
|
Function naming and function prototype shaping is perhaps the best way to ensure
|
|
that these are separated properly.
|
|
|
|
If these naming and prototype design conventions are followed, then a program
|
|
ought to be able to written without checking the results of operations; and the
|
|
programmer should be able to trust that exceptions will handle violations of xis
|
|
assumptions out of band.
|
|
|
|
## Find vs Get:
|
|
|
|
findFoo(): Looks for Foo and returns a data type which is expected both to
|
|
tolerate and communicate emptiness.
|
|
E.g: std::optional, std::shared/unique_ptr.
|
|
* Does not throw if Foo is not found because caller's expectations are
|
|
tentative.
|
|
```
|
|
std::optional<Foo> SomeManager::findFoo(std::string searchCriteria)
|
|
{
|
|
for (item: collection)
|
|
{
|
|
if (item.property != searchCriteria) { continue; }
|
|
return item;
|
|
}
|
|
}
|
|
```
|
|
|
|
getFoo/retrieveFoo(): Looks for foo and throws if foo isn't found because caller
|
|
expects foo exist, and non-existence is a program error. Conceptually is a
|
|
wrapper around findFoo() that throws if !findFoo(). In practice due to
|
|
locking requirements it may often be necessary to implement getFoo() with
|
|
its own function body and not reuse findFoo().
|
|
* Returns references or smart pointers, or similar types.
|
|
```
|
|
Foo &SomeManager::getFoo(std::string searchCriteria)
|
|
{
|
|
auto ret = findFoo(searchCriteria);
|
|
if (!ret) { throw("Foo not found with criteria " +searchCriteria); }
|
|
return ret.get();
|
|
}
|
|
```
|
|
|
|
## |