Different Levels Of Exception Safety Guarantees In C++ - C++ Programming Tutorial
C++ Course / Exception Handling / Different Levels Of Exception Safety Guarantees In C++

Different Levels Of Exception Safety Guarantees In C++

BLUF: Mastering Different Levels Of Exception Safety Guarantees In C++ is a critical step in becoming a proficient C++ developer. This lesson provides a deep dive into the syntax, performance considerations, and real-world applications of this concept.
Key Performance Insight: Different Levels Of Exception Safety Guarantees In C++

C++ is renowned for its efficiency. Learn how Different Levels Of Exception Safety Guarantees In C++ enables low-level control and high-performance computing in the tutorial below.

Exception safety in C++ programming is a vital aspect that ensures the integrity and reliability of code when exceptions occur. This guide will outline different tiers of exception safety, best practices, and delve into the realm of exception handling.

Robust C++ programming requires exception safety, which makes sure that code behaves consistently and maintains its integrity even when exceptions arise. It includes the following three levels of guarantees:

  • Basic Exception Safety
  • Strong Exception Safety
  • No-Throw Guarantee
  • 1. Basic Exception Safety:

At this point, resource leakage is absent, ensuring the program's continued functionality, although there may be consequential side effects stemming from unfinished operations.

Example:

Let's consider a scenario to demonstrate the fundamental concept of exception safety in C++.

Example

#include <iostream>
#include <fstream>
#include <string>
void openFileAndPrinting()
{
    std::ofstream file("output.txt");
    if (!file.is_open())
    {
        throw std::runtime_error("Failed to open the file.");
    }
    // Close the File even if an exception is raised by using RAII (Resource Acquisition Is Initialization).
    struct FileCloser 
    {
        std::ofstream& fileRef;
        FileCloser(std::ofstream& file) : fileRef(file) {}
        ~FileCloser() { fileRef.close(); }
    } fileCloser(file); 
    // RAII object created here.
    // Writing data into the File.
    file << "Hello, Exception Safety!" << std::endl;
    // An exception might be thrown here.
}
int main() 
{
    try
    {
        openFileAndPrinting();
    }
    catch (const std::exception& e)
    {
        std::cerr << "Exception: " << e.what() << std::endl;
    }
    // Even in the event of an exception, the File is properly closed.
    return 0;
}

Output:

Output

Exception: Failed to open the File.

Explanation:

This sample code illustrates key concepts of C++ exception safety. The code attempts to open the "output.txt" file for writing by using the openFileAndPrinting function. If the file cannot be opened, it throws a std::runtime_error. Subsequently, a nested structure called FileCloser is created, which employs RAII to automatically close the File during its destruction to ensure proper resource handling. The FileCloser instance guarantees that the File is closed when the Function exits, regardless of success or exceptions. Following this, data is written to the File, potentially triggering an exception. The main function is then invoked within a try-catch block to manage any exceptions that may occur. In case of an exception, an error message is output to the standard error stream. This approach guarantees the correct closure of the file, upholding program stability and preventing resource leaks.

2. Strong Exception Safety:

This degree of exception safety enhances reliability. In the event of an exception, it guarantees proper resource release and maintains the program's state intact, as though the operation had not occurred.

Example:

Let's consider a scenario to demonstrate the robust exception handling capability in C++.

Example

#include <iostream>
#include <fstream>
#include <string>
#include <memory> 
// for std::unique_ptr
//Function to open a file and write data to it.
void openFileAndPrint() 
{
    std::ofstream file("output.txt");
    if (!file.is_open())
    {
        throw std::runtime_error("Failed to open the file.");
    }
    // Writing data into the File.
    file << "Hello, Exception Safety!" << std::endl;
    // An exception might be thrown here.
}
//Function to read the data from the File.
void readFile()
{
    std::ifstream file("output.txt");
    if (!file.is_open())
    {
        throw std::runtime_error("Failed to open the file for reading.");
    }
    // Reading data from the File.
    std::string line;
    while (std::getline(file, line))
    {
        std::cout << "Read from file: " << line << std::endl;
    }
    // An exception might be thrown here.
}
int main()
{
    // Using try-catch blocks to handle exceptions separately.
    try 
    {
        openFileAndPrint();
        readFile();
    }
    catch (const std::runtime_error& openError)
    {
        std::cerr << "Error opening file: " << openError.what() << std::endl;
    } 
    catch (const std::exception& readError)
    {
        std::cerr << "Error reading from file: " << readError.what() << std::endl;
    }
    //File is automatically closed when the unique_ptr goes out of scope.
    return 0;
}

Output:

Output

Error opening file: Failed to open the File.

Explanation:

This code illustrates the fundamental exception handling capabilities of C++. It tries to open the file "output.txt" for writing by utilizing the openFileAndPrint function. In case the file opening operation fails, a std::runtimeerror is thrown with the relevant error description. Subsequently, the phrase "Hello, Exception Safety!" is appended to the file. Similarly, the readFile function reads each line from the file and displays it on the console after attempting to open the file for reading. If the file cannot be opened for reading, a std::runtimeerror is raised.

Both the functions readFile and openFileAndPrint are invoked within a try-catch block within the main function. If an exception is thrown by either function, it is captured and managed appropriately. An error seems to arise when attempting to open the file in case openFileAndPrint triggers an exception. Conversely, if readFile generates an exception, it suggests a problem with reading from the file.

The code implements fundamental exception handling by employing separate try-catch blocks for individual function calls, guaranteeing proper exception handling. Moreover, potential resource leaks are prevented as the File is promptly closed following RAII (Resource Acquisition Is Initialization) guidelines when the std::ofstream and std::ifstream objects go out of scope.

3. No-Throw Guarantee:

Functions at this topmost level are assured to not raise exceptions. This guarantees the maintenance of the program's resources and state, even in extraordinary situations.

Input Required

This code uses input(). Please provide values below:

Logic Practice
Install Logic Practice
Add to home screen for a faster app-like experience