# Strong Exception Safety in C++

Strong exception safety means **commit or rollback**:

* If an operation succeeds, all changes become visible.
* If an operation throws, observable program state remains exactly as before.

This article organizes the core guarantees and shows practical C++ patterns to get strong exception safety without overengineering.

## 1) The exception-safety levels

In practice, code falls into one of these levels:

1. **No guarantee**
   * An exception may leak resources or leave objects in an invalid state.
2. **Basic guarantee**
   * No resource leaks, invariants are preserved, but object value may change.
3. **Strong guarantee**
   * Operation is transactional: either full success or no visible effect.
4. **No-throw guarantee (`noexcept`)**
   * Operation never lets exceptions escape.

`noexcept` is the strongest contract, but it is usually feasible only for a subset of operations (destructors, swaps, many moves, cleanup paths).

## 2) The classic strong-guarantee technique: copy-and-swap

For assignment-like updates, copy-and-swap is the most common pattern.

```cpp
#include <string>
#include <utility>

class UserProfile {
public:
    UserProfile() = default;
    explicit UserProfile(std::string name) : name_(std::move(name)) {}

    // Strong guarantee: if copy construction of rhs throws,
    // *this is unchanged.
    UserProfile& operator=(UserProfile rhs) {
        swap(rhs);
        return *this;
    }

    void swap(UserProfile& other) noexcept {
        using std::swap;
        swap(name_, other.name_);
    }

private:
    std::string name_;
};
```

Why it works:

* Potentially-throwing work happens while constructing `rhs`.
* After that, `swap` is `noexcept` and commits atomically from caller perspective.

## 3) `std::move`, throwing moves, and `std::move_if_noexcept`

`std::move` itself never throws; it is only a cast. What can throw is the move constructor/assignment of the target type.

This matters for containers during reallocation. To keep strong guarantees, implementations often prefer copy when move is not `noexcept`.

```cpp
#include <type_traits>
#include <utility>

template <class T>
void relocate(T& src, T& dst) {
    // Moves when move is noexcept (or copy is unavailable),
    // otherwise copies to preserve stronger safety.
    dst = std::move_if_noexcept(src);
}
```

Guideline: mark move operations `noexcept` when you can truly guarantee it. This enables better performance and helps containers preserve strong guarantees.

## 4) RAII is the foundation

Strong/basic guarantees rely on reliable cleanup. RAII is the standard mechanism.

```cpp
#include <fstream>
#include <stdexcept>
#include <string>

std::string read_first_line(const std::string& path) {
    std::ifstream in(path);  // Resource acquired here.
    if (!in) {
        throw std::runtime_error("open failed");
    }

    std::string line;
    std::getline(in, line);
    return line; // Resource released automatically by destructor.
}
```

If an exception is thrown, stack unwinding destroys local objects and releases resources automatically.

## 5) Destructor and catch guidance

* Destructors should not throw. If cleanup might throw, catch inside the destructor.
* Catch exceptions only when you can recover meaningfully.
* Otherwise, let exceptions propagate to a layer that can decide policy.

## 6) Practical checklist

* Define class invariants first; guarantees are meaningless without invariants.
* Prefer value types and RAII members (`std::string`, `std::vector`, smart pointers).
* Use copy-and-swap for transactional updates.
* Make `swap` and move operations `noexcept` where correct.
* Use `std::move_if_noexcept` in generic relocation/update code.

## References

* [Levels of Exception Safety](https://arne-mertz.de/2015/12/levels-of-exception-safety/)
* [How to: Design for exception safety (Microsoft)](https://learn.microsoft.com/en-us/cpp/cpp/how-to-design-for-exception-safety?view=msvc-170)
* Effective Modern C++, Item 14: declare functions `noexcept` if they will not emit exceptions.
* [Modern C++ best practices for exceptions and error handling](https://learn.microsoft.com/en-us/cpp/cpp/errors-and-exception-handling-modern-cpp?view=msvc-170)
* [How to: Interface between exceptional and non-exceptional code](https://learn.microsoft.com/en-us/cpp/cpp/how-to-interface-between-exceptional-and-non-exceptional-code?view=msvc-170)
* [Rule of Three/Five/Zero](https://en.cppreference.com/cpp/language/rule_of_three) and [The Rule of Five in C++](https://www.geeksforgeeks.org/cpp/rule-of-five-in-cpp/)


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://www.damonyuan.com/tech/260303-strong-exception-safty.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
