C++
Error handling
Add input validation and error handling with try/catch.
Validation with a custom exception
In this lesson we will add validation to the addTask function. If the title is empty, an InvalidTaskException will be thrown; the caller catches it with try/catch and shows a message to the user.
InvalidTaskException is a class derived from std::exception; it overrides the what() method to return a custom message. This way the program can respond appropriately to invalid inputs without crashing.
Catching with try/catch
You wrap the addTask call in a try block; when an exception is thrown, the catch block runs. With catch (const InvalidTaskException& e), the message is accessed via e.what().
try {
addTask(tasks, "", "pending");
} catch (const InvalidTaskException& e) {
cout << e.what();
}
Here an empty title throws InvalidTaskException; catch catches it and prints the message. The program continues without crashing. This pattern is the standard way to validate user input.
Exercise Add the InvalidTaskException class
Define class InvalidTaskException : public std::exception; in a public: block write const char* what() const noexcept override { return "invalid task"; }. At the start of addTask, add if (title.empty()) throw InvalidTaskException();. In main, after printMenu();, add try { addTask(tasks, "Homework", "pending"); addTask(tasks, "", "pending"); } catch (const InvalidTaskException& e) { cout << e.what() << endl; } and a final listTasks(tasks); call.
Show example solution
#include <iostream>
#include <string>
#include <vector>
#include <stdexcept>
using namespace std;
struct Task {
string title;
string status;
};
class InvalidTaskException : public std::exception {
public:
const char* what() const noexcept override {
return "invalid task";
}
};
void printMenu() {
cout << "1 - Add" << endl;
cout << "2 - List" << endl;
cout << "3 - Exit" << endl;
}
void addTask(vector<Task>& tasks, string title, string status) {
if (title.empty()) throw InvalidTaskException();
Task t;
t.title = title;
t.status = status;
tasks.push_back(t);
}
void listTasks(const vector<Task>& tasks) {
for (Task t : tasks) {
cout << t.title << " - " << t.status << endl;
}
}
int main() {
printMenu();
vector<Task> tasks;
try {
addTask(tasks, "Homework", "pending");
addTask(tasks, "", "pending");
} catch (const InvalidTaskException& e) {
cout << e.what() << endl;
}
listTasks(tasks);
return 0;
}
Test yourself
-
Fill in the blank: throw call
if (title.empty()) {
____ InvalidTaskException();
}
Show answer
if (title.empty()) {
throw InvalidTaskException();
}
-
How is an empty title reported in addTask?
- The program crashes
- Returns 0
- Ignores
- Throws InvalidTaskException
Show answer
Throws InvalidTaskException — On empty title, InvalidTaskException is thrown.
-
Match each block with its job
- try
- addTask call
- throw
- throws the exception
- catch
- prints the message
Next lesson: Putting it together