Exercise: Search, “User Not Found” Exception

What’s Wrong?

In Exercise: Search a User By Lastname we chose to implement the UserDB::search_by_lastname() method to return an instance of User,

class UserDB
{
public:
    ...
    User search_by_lastname(const std::string& lastname) const;
    ...
};

This leads to unnatural coding in the not-found case: an empty/invalid user has to be returned:

User UserDB::search_by_lastname(const std::string& lastname) const
{
    for (size_t i=0; i<_users.size(); i++)
        if (_users[i].lastname() == lastname)
            return _users[i];    // ok, we have something that we can return

    return User();    // unnatural: what user is that?
}

Why is that unnatural?

  • I only want to give something that I own. If that was possible, I could return a const User& instead of a fat copy of something that I artificially create (and destroy soon thereafter).

  • If the caller wants to differentiate between “found” and “not found” (occasionally callers exhibit such desires), currently this has to be done by checking the validity of the returned object (using wrinkles such as User::isvalid()):

    User user = db.search_by_lastname("Faschingbauer");
    if (user.isvalid()) {
        // do something with it
    }
    else {
        // error handling, possibly
    }
    

Exercise

  • Create a new file, errors.h (which will hold all future exception classes).

  • In that file, implement (inline only) a custom exception, class UserNotFound (see here for how to create a custom exception).

  • Modify UserDB::search_by_lastname() to throw an instance of it in the not-found case.

  • Test this using the program below (feel free to use your own version of it):

#include "userdb.h"
#include <iostream>

int main()
{
    UserDB db;

    try {
        User user = db.search_by_lastname("Faschingbauer");

        // unreached because database is empty
        std::cout << "yay!" << user.lastname() << std::endl;
        return 0;
    }
    except (const UserNotFound& e) {
        std::cerr << "argh: no \"Faschingbauer\" in there" << std::endl;
        return 1;
    }
}