> For the complete documentation index, see [llms.txt](https://www.damonyuan.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://www.damonyuan.com/tech/2026/260303-strong-exception-safty.md).

# 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/)
