Week 12: File Handling, Exceptions, and Your Path Forward

Learn to interact with files, handle errors gracefully, and plan your continued C++ journey.

Explore Chapter 12

Chapter 12: Working with Files and Looking Ahead

File I/O (`fstream`).

Many applications need to read data from files or write results to files. C++ provides the `fstream` library for file input/output operations.

You typically need to include the `` header.

#include <fstream> // For file stream operations
#include <iostream> // For std::cout, std::cerr
#include <string>    // For std::string

Writing to Files (`ofstream`)

Use `std::ofstream` (output file stream) to write data to a file. If the file doesn't exist, it's created. If it does exist, its contents are typically discarded by default (use `std::ios::app` mode to append).

// Create and open a file for writing
std::ofstream outputFile("output.txt");

if (outputFile.is_open()) { // Always check if the file opened successfully
    outputFile << "This is the first line.\n";
    outputFile << "Writing some data: " << 123 << "\n";
    outputFile.close(); // Close the file when done
    std::cout << "Successfully wrote to output.txt\n";
} else {
    std::cerr << "Unable to open file for writing!\n";
}

Reading from Files (`ifstream`)

Use `std::ifstream` (input file stream) to read data from a file.

std::string line;
std::ifstream inputFile("output.txt"); // Open the file we just wrote

if (inputFile.is_open()) {
    std::cout << "Reading from output.txt:\n";
    // Read line by line
    while (std::getline(inputFile, line)) {
        std::cout << line << '\n';
    }
    inputFile.close(); // Close the file
} else {
    std::cerr << "Unable to open file for reading!\n";
}

Remember to check if files opened correctly using `is_open()` and to `close()` files when you're finished. Using file streams within objects whose destructors automatically close the file (RAII principle) is a more robust approach, especially when dealing with potential errors.

Basic Error Handling (`try`, `catch`, `throw`).

Errors and exceptional situations can occur during program execution (e.g., trying to open a non-existent file, dividing by zero, invalid user input). C++ provides exception handling mechanisms to deal with these situations gracefully.

Core Components

  • `try` Block: Encloses the code that might potentially throw an exception.
  • `catch` Block: Follows a `try` block. Contains the code to handle a specific type of exception if one is thrown within the `try` block. You can have multiple `catch` blocks for different exception types.
  • `throw` Statement: Used to signal that an exceptional situation has occurred. You typically throw an object (often an instance of a class derived from `std::exception`).

Example

#include <iostream>
#include <stdexcept> // For standard exception classes like std::runtime_error

double divide(double numerator, double denominator) {
    if (denominator == 0.0) {
        throw std::runtime_error("Math error: Attempted to divide by zero"); // Throw an exception
    }
    return numerator / denominator;
}

int main() {
    double a = 10.0;
    double b = 0.0;
    double result;

    try {
        std::cout << "Attempting division..." << std::endl;
        result = divide(a, b); // This might throw
        std::cout << "Result: " << result << std::endl; // Won't execute if exception occurs
    }
    catch (const std::runtime_error& e) { // Catch the specific exception type
        std::cerr << "Exception caught: " << e.what() << '\n'; // .what() gets the error message
    }
    // Can have more catch blocks for different exception types
    // catch (...) { // Catches any type of exception (use sparingly)
    //    std::cerr << "An unknown error occurred.\n";
    // }

    std::cout << "Program continues after try-catch block." << std::endl;
    return 0;
}

Exception handling allows your program to recover from errors or terminate in a more controlled manner instead of crashing abruptly.

Mini-Project Idea.

To consolidate your learning, try creating a small project. This helps reinforce concepts and exposes practical challenges.

Idea: Simple Contact Management System

  1. Define a `Contact` class: With private members for name, phone number, email. Include a constructor and public getter methods.
  2. Use `std::vector` or `std::map`: Store multiple `Contact` objects in an STL container (e.g., `std::vector`).
  3. Implement Core Features (Functions):
    • `addContact()`: Prompts the user for details and adds a new `Contact` object to your container.
    • `viewContacts()`: Iterates through the container and displays all contact details neatly.
    • `searchContact()`: Prompts for a name and displays the details if found.
    • (Optional) `saveToFile()`: Writes the contact list to a text file using `ofstream`.
    • (Optional) `loadFromFile()`: Reads the contact list from the text file using `ifstream` when the program starts.
  4. Create a Menu (`main` function): Use a loop (`do...while` is good here) to present a menu to the user (Add, View, Search, Exit) and call the appropriate functions based on their input.
  5. (Optional) Add Basic Error Handling: Use `try-catch` for file operations or potentially invalid input.

This project integrates classes, STL containers, file I/O, functions, and control flow.

Where to Go Next?

Congratulations on completing this 12-week introduction to C++!

You now have a strong foundation. The world of C++ is vast and deep. Here are some areas to explore further:

  • Advanced STL: Explore more containers (`queue`, `stack`, `priority_queue`), advanced algorithms, and allocators.
  • Templates In-Depth: Master function templates and class templates for writing truly generic code.
  • Advanced OOP: Multiple inheritance, virtual inheritance, operator overloading, design patterns.
  • Modern C++ Features: Dive deeper into C++11, C++14, C++17, C++20 features (smart pointers, lambdas, concurrency features, modules, concepts, ranges, etc.).
  • Build Systems: Learn tools like CMake or Make for managing larger projects.
  • Debugging Tools: Get proficient with debuggers like GDB or the debugger integrated into your IDE.
  • Specific Application Domains:
    • Game Development: Unreal Engine (C++), custom engines, graphics libraries (OpenGL, Vulkan, DirectX).
    • System Programming: OS interaction, networking, low-level optimization.
    • High-Performance Computing: Parallel programming (OpenMP, MPI), libraries like Boost.
    • Embedded Systems: Programming microcontrollers and resource-constrained devices.
  • Contribute to Open Source: Find a C++ project you're interested in and contribute!

The best way to learn is by building projects that interest you. Keep coding, keep experimenting, and keep learning!

Syllabus