Question

AccountHolder Search(int accno, string CNIC, AccountHolder* customer, int counter) {
for (int i = 0;i < counter;i++) {
    if (account == customer[i].getAccno() && CNIC == customer[i].getCNIC()) {
        return customer[i];
    }
}
return (-----);
}

The problem is I want to return something which tells me that the account number and CNIC do not match with any customer id. I can do it by creating a new object and as my constructor sets all data members to zero or empty string, I may be able to check that such customer is not present but is there any other way? It's my first question, so I hope i haven't asked a stupid question. Thanks!

Was it helpful?

Solution

There are many ways of doing this, some are nicer than others but it depends on your situation.

If it is something that doesn't happen very often and is an actual error (this is key, as it is slow), throw an exception.

You could instead return a const pointer to an object, and return NULL in the case of an error. This only makes sense if the original object is guarenteed not to disappear during its usage.

You could instead return a bool and take your AccountHolder by reference and fill it in if there is a match.

You could also take a boolean by reference, I don't really like this option as its quite a strange interface choice.

I'm sure there are other choices.

OTHER TIPS

I want to return something which tells me that the account number and CNIC do not match with any customer id

Well there are two ways to consider this problem:

  • use an exception

if your Search() shall always have valid arguments (i.e. existing account number and CNIC), and never have wrong values, it shall fail loudly when it has a wrong set of arguments by throwing an exception:

AccountHolder Search(int accno, string CNIC, AccountHolder* customer, int counter) {
    for (int i = 0;i < counter;i++) {
        if (account == customer[i].getAccno() && CNIC == customer[i].getCNIC()) {
            return customer[i];
        }
    }
    throw std::invalid_argument("Unknown account");
}

of course, a custom designed exception is even better.

  • Use a singleton

but if that situation is part of your design and this is not an error, but a feature, then it shall return a value that you can test against to tell you that the customer does not exist:

So you shall design your AccountHolder class with a custom field that you can check so you can create a global unknownAccountHolder instance that you return from this function and then can check against. As you do not give your AccountHolder design.

class AccountHolder {
    static const AccountHolder unknownAccountHolder(-1, "invalid");
    […]
}

AccountHolder Search(int accno, string CNIC, AccountHolder* customer, int counter) {
    for (int i = 0;i < counter;i++) {
        if (account == customer[i].getAccno() && CNIC == customer[i].getCNIC()) {
            return customer[i];
        }
    }
    return AccountHolder::unknownAccountHolder;
}
  • use C style error handling is a wrong third option

you may use other options suggested to you: using a returned pointer, passing a boolean as parameter, returning a boolean and taking the object as argument… But that's all c-style coding and bad design as it's complicating your Search() function prototype and/or adding more memory management than necessary. You're doing C++ here, so try to keep it simple and use good OOP practice.

pass a boolean result by reference as a parameter
AccountHolder Search(int accno, string CNIC, AccountHolder* customer, int counter, bool &isMatch)
{
///
}

Turn your return type into a pointer, or even better a smart pointer, and return NULL or an equivalent smart pointer:

AccountHolder * Search(int accno, string CNIC, AccountHolder* customer, int counter) {
  for (int i = 0;i < counter;i++) {
    if (account == customer[i].getAccno() && CNIC == customer[i].getCNIC()) {
      return &customer[i];
    }
  }
  return NULL;
}

In order to use smart pointers you'd have to change how customer is defined, e.g. by making it a std::vector<std::shared_ptr<AccountHolder> >. If your compiler doesn't provide std::shared_ptr you would need to use Boost.

One option would be to return bool to indicate if the search is successful or not. In this case you would need an extra output parameter, which will store the result if the function returns true.

bool Search(int accno, string CNIC, AccountHolder* customer, int counter, AccountHolder *result);

If you have boost handy, one thing worth considering is boost::optional<>. This is nice as it documents also exactly what the return could be. You can return a boost::none, in the event that you don't have anything useful to return.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top