wk11_modern_C++_2


Modern C++ Features, Part 2

C++ program that demonstrates the use of lambda expressions for numerical integration and exception handling using std::exception_ptr. Here's the implementation:

Resources (C++ Tutorial)

algorithm, auto, command_line_arguments, exception, iostream, namespace, range-based, sstream, std::cin, std::cout, std::cerr, std::exception, std::ifstream, std::ofstream, stdexcept, throw, vector

Implementation

#include <iostream>
#include <functional>
#include <cmath>
#include <exception>
#include <stdexcept>

// Trapezoidal rule implementation using lambda
double trapezoidal_rule(std::function<double(double)> f, double a, double b, int n) noexcept {
    try {
        if (n <= 0) {
            throw std::invalid_argument("Number of subdivisions must be positive");
        }

        double h = (b - a) / n;
        double sum = 0.5 * (f(a) + f(b));

        for (int i = 1; i < n; ++i) {
            sum += f(a + i * h);
        }

        return h * sum;
    } catch (...) {
        return std::numeric_limits<double>::quiet_NaN();
    }
}

// Function to safely execute integration and handle exceptions
std::pair<double, std::exception_ptr> safe_integrate(std::function<double(double)> f, double a, double b, int n) {
    std::exception_ptr eptr;
    double result = 0.0;

    try {
        result = trapezoidal_rule(f, a, b, n);
        if (std::isnan(result)) {
            throw std::runtime_error("Integration failed");
        }
    } catch (...) {
        eptr = std::current_exception();
    }

    return {result, eptr};
}

int main() {
    // Define the function to integrate using a lambda expression
    auto f = [](double x) { return x * x; };

    double a = 0.0;
    double b = 1.0;
    int n = 1000;

    auto [result, eptr] = safe_integrate(f, a, b, n);

    if (eptr) {
        try {
            std::rethrow_exception(eptr);
        } catch (const std::exception& e) {
            std::cout << "Exception caught: " << e.what() << std::endl;
        }
    } else {
        std::cout << "Integration result: " << result << std::endl;
    }

    // Test with invalid input
    std::tie(result, eptr) = safe_integrate(f, a, b, -1);

    if (eptr) {
        try {
            std::rethrow_exception(eptr);
        } catch (const std::exception& e) {
            std::cout << "Exception caught: " << e.what() << std::endl;
        }
    } else {
        std::cout << "Integration result: " << result << std::endl;
    }

    return 0;
}

This program demonstrates the following concepts:

  1. Lambda Expressions:
  2. We use a lambda expression to define the function to integrate: auto f = [](double x) { return x * x; };
  3. This allows for inline definition of the function without needing a separate function declaration.

  4. std::exception_ptr and noexcept:

  5. The trapezoidal_rule function is marked as noexcept, indicating that it will handle all exceptions internally.
  6. We use std::exception_ptr in the safe_integrate function to capture any exceptions that occur during integration.
  7. The main function demonstrates how to safely handle these exceptions using std::rethrow_exception.

  8. Numerical Integration:

  9. The program implements the trapezoidal rule for numerical integration.
  10. It handles potential errors such as invalid input (negative number of subdivisions).

  11. Error Handling:

  12. The program can recover from errors like invalid input parameters.
  13. It uses std::numeric_limits<double>::quiet_NaN() to indicate integration failure in a way that can be checked later.

This implementation provides a robust framework for numerical integration that can handle errors gracefully, which is crucial in scientific computing applications where reliability and error recovery are important.

Related

Previous Page | Course Schedule | Course Content