CS253: Software Development with C++

Fall 2022

Old-fashioned Error Handling

Show Lecture.Old-fashionedErrorHandling as a slide show.

CS253 Old-fashioned Error Handling

#includes

To use NAN and isnan(), you need to:

#include <cmath>

The Old Days

Out-of-band value

Out-of-band value

Loud a='a';

double invert(double num) {
    Loud b('b');
    if (num == 0)
        return NAN;
    return 1/num;
}

int main() {
    Loud c('c');
    double result = invert(0);
    if (isnan(result))  // failure?
        return 1;
    cout << result << '\n';
}
Loud::Loud() [c='a']
Loud::Loud() [c='c']
Loud::Loud() [c='b']
Loud::~Loud() [c='b']
Loud::~Loud() [c='c']
Loud::~Loud() [c='a']

That works, but …

Unacceptable out-of-band values

Remember that nullptr and NULL aren’t magic (and null doesn’t exist). You can only return a null pointer if you’re returning a pointer. It won’t work for returning a number, object, or reference.

double foo() { return NULL; }
double bar() { return nullptr; }
int main() { }
c.cc:1: warning: converting to non-pointer type ‘double’ from NULL
c.cc:2: error: cannot convert ‘std::nullptr_t’ to ‘double’ in return

For a floating-point value, NAN (not a number) is often a good sentinel value.

Unacceptable out-of-band values

For an int, nullptr isn’t possible, and NAN is only for floating-point values:

int bar() {
    return nullptr;
}

int main() {
    cout << bar();
}
c.cc:2: error: cannot convert ‘std::nullptr_t’ to ‘int’ in return

A good sentinel depends on the possible return values. -1 is fine for an integer square root routine, and zero works for the year a loan is due.

Unacceptable out-of-band values

This compiles, because string has a ctor that takes a const char *, and nullptr converts to that. However, it fails at runtime:

string baz() {
    return nullptr;
}

int main() {
    cout << baz();
}
terminate called after throwing an instance of 'std::logic_error'
  what():  basic_string::_M_construct null not valid
SIGABRT: Aborted

Giving Up

exit

Loud a='a';

double invert(double num) {
    Loud b('b');
    if (num == 0) {
        cerr << "Can’t invert zero!\n";
        exit(1);
    }
    return 1/num;
}

int main() {
    Loud c('c');
    cout << invert(0) << '\n';
}
Loud::Loud() [c='a']
Loud::Loud() [c='c']
Loud::Loud() [c='b']
Can’t invert zero!
Loud::~Loud() [c='a']

abort

Loud a='a';

double invert(double num) {
    Loud b('b');
    if (num == 0) {
        cerr << "Can’t invert zero!\n";
        abort();
    }
    return 1/num;
}

int main() {
    Loud c('c');
    cout << invert(0) << '\n';
}
Loud::Loud() [c='a']
Loud::Loud() [c='c']
Loud::Loud() [c='b']
Can’t invert zero!
SIGABRT: Aborted

assert

Loud a='a';

double invert(double num) {
    Loud b('b');
    assert(num!=0);
    return 1/num;
}

int main() {
    Loud c('c');
    cout << invert(0) << '\n';
}
Loud::Loud() [c='a']
Loud::Loud() [c='c']
Loud::Loud() [c='b']
a.out: c.cc:5: double invert(double): Assertion `num!=0' failed.
SIGABRT: Aborted