Fact-checked by Grok 2 weeks ago

Exception safety

Exception safety is a programming , primarily associated with exception-handling mechanisms in languages such as C++, that ensures operations leave the program in a valid and consistent state even if an exception is thrown, preventing resource leaks, maintaining class invariants, and avoiding . It addresses the challenges of error recovery by providing formal guarantees about the post-exception state of objects and , enabling reliable in the presence of runtime errors. The concept is formalized through three primary levels of guarantees, each offering increasing assurances about program behavior during exceptions. The basic guarantee ensures that, upon exception, the program remains in a usable state with no resource leaks and all invariants preserved, though partial modifications may occur. The strong guarantee provides transaction-like semantics, meaning the operation either completes fully or has no observable effect on the program state, effectively rolling back any changes if an exception arises. Finally, the no-throw guarantee (also called nothrow or nofail) stipulates that the operation will never throw an exception, which is required for critical components like destructors in the C++ standard library since C++11. These levels are hierarchical, with stronger guarantees implying the weaker ones, and they form the foundation for exception-safe code in generic and container-based programming. In the , exception safety is a core requirement, with most operations providing at least the basic guarantee and certain container methods such as std::vector::push_back offering the strong guarantee under specified conditions. Achieving these guarantees often relies on techniques like the (RAII) idiom, which ties resource management to object lifetimes, and the use of smart pointers to automate cleanup. The framework was articulated by in the late 1990s, influencing the design of modern C++ to support robust, exception-resilient software.

Fundamentals

Definition and Core Concepts

Exceptions serve as a control flow mechanism for error handling in programming languages, enabling the transfer of execution from the point of an error to a designated handler, thereby isolating exceptional conditions from normal program flow. Exception safety refers to the guarantees provided by a function or operation concerning the program's state when an exception is thrown during its execution, ensuring that the program does not enter an inconsistent or corrupted condition. Specifically, an operation is considered exception-safe if it leaves affected objects in a valid, well-defined state upon termination by an exception, facilitating proper error recovery or cleanup. This concept emphasizes predictable behavior in the presence of failures, preventing issues such as resource leaks or partial modifications that could compromise program integrity. Central to exception safety are the distinctions between the pre-exception state—the observable program state prior to initiating the operation, where invariants are already established—and the post-exception state, which must remain valid and usable despite the interruption. Invariants, defined as consistent properties that hold true for an object throughout its lifetime, are maintained by constructors at creation and preserved by all subsequent operations; in an exception-safe design, these invariants endure even after an exception, ensuring object consistency without requiring full restoration to the original state. This preservation allows the program to continue execution meaningfully, with the post-exception state supporting further operations or error handling. A key principle underlying exception safety is that an operation terminated by an exception must leave the program in a valid state, upholding invariants and avoiding resource leaks or undue side effects. These concepts were introduced in the development of for C++, providing a foundation for robust error management in .

Importance in Robust Programming

Exception safety is crucial in robust programming because it ensures that when exceptions occur during error conditions, the program's state remains consistent, preventing resource leaks such as unreleased or file handles, and avoiding that could lead to . By maintaining program invariants even after an exception is thrown, exception safety allows developers to write code that handles failures gracefully without leaving the system in a partially updated or invalid state, thereby enhancing overall reliability and reducing the risk of cascading errors. In larger systems, particularly multithreaded or distributed applications, exception safety supports fault-tolerant designs by enabling clean error propagation across components, allowing intermediate functions to unwind the stack properly and invoke destructors for resource cleanup without requiring explicit coordination between distant code layers. This facilitates the of composable and reusable modules, such as those in libraries, where operations can fail without compromising the of the entire application, promoting and maintainability in complex environments. Poor exception safety can result in severe consequences, including persistent memory leaks that accumulate over time and exhaust system resources, or inconsistent states like partially committed database transactions that lead to issues and potential vulnerabilities. For instance, if an exception interrupts a operation midway, it may leave the corrupted, rendering subsequent accesses unsafe and potentially causing program crashes or exploitable errors in production systems. Exception safety aligns closely with principles like RAII, which binds resource acquisition to object initialization and release to destruction, providing an automatic mechanism to achieve safety guarantees with low runtime overhead and enabling predictable behavior during exception unwinding. This integration not only simplifies error-prone manual management but also reinforces broader goals of , ensuring that code remains robust against unforeseen failures.

Historical Context

Origins in Exception Handling

The concept of , which forms the foundation for exception safety, originated in the 1970s with languages like CLU, developed at under . In CLU, exceptions served primarily as a mechanism for error propagation in a termination-based model, allowing procedures to signal abnormal conditions and propagate them to callers if unhandled, thereby enabling modular error recovery without automatic failure signaling. However, CLU's design emphasized practical abstraction and reliability through explicit exception declarations in cluster specifications, but it lacked formal guarantees for or state consistency during unwinding. This approach influenced subsequent languages, including Ada in the 1980s, where exception handling was formalized in the Ada 83 standard to address error conditions in safety-critical systems. Ada's exceptions, derived from earlier proposals such as those by , Fokkinga, and de Haas in 1976, enabled raising and handling runtime errors like constraint violations, with propagation across subprogram calls but without built-in assurances for exception-safe cleanup or object invariants. These early systems prioritized structured error flow over comprehensive safety, setting the stage for integrating exceptions into object-oriented paradigms. In C++, exception handling was introduced by during the language's design evolution from 1984 to 1989, driven by the need for robust error management in object-oriented code, particularly for resource acquisition and release in library-based programs. Stroustrup's decisions emphasized type-safe exception objects derived from classes, multi-level propagation, and zero runtime overhead for non-throwing paths, rejecting resumption semantics in favor of termination to simplify implementation and align with C's efficiency. A core motivation was enabling safe unwinding through automatic destructor calls on local objects, leveraging the "resource acquisition is initialization" (RAII) idiom to ensure cleanup without manual intervention, though destructors throwing during unwinding would invoke termination. Prior to the 1998 standard, exception handling appeared in C++ implementations like Release 4.0 (1993) and was detailed in the Annotated C++ Reference Manual (ARM) of 1990 by Margaret Ellis and Stroustrup, which specified mechanics including stack unwinding and destructor invocation to maintain program integrity. These pre-standard practices, influenced by informal drafts and committee discussions starting in , focused on compatibility with C and minimal overhead, establishing destructor calls as a foundational element for informal safety without codified guarantees. The key milestone came with the ISO/IEC 14882:1998 standard, the first international codification of C++ exception handling, which formalized the syntax (try-catch blocks), semantics (type matching and propagation), and runtime behavior, including mandatory destructor calls during unwinding to support reliable error recovery. This standardization built directly on the and earlier designs, providing a unified that addressed the limitations of prior languages by integrating exceptions with C++'s object model.

Evolution in C++ Standards

The exception safety guarantees in C++ were first formalized in the C++98 standard, where stack unwinding during exception propagation ensures that destructors for objects with automatic storage duration are invoked, thereby releasing resources and maintaining basic invariants without leaks. This mechanism, rooted in the language's model, provides the foundation for the basic exception safety guarantee by automatically cleaning up partially constructed objects, though destructors themselves must not throw to avoid invoking std::terminate. The standard, primarily a defect report update to C++98, preserved these rules without significant changes to exception safety semantics. C++11 introduced the noexcept specifier, allowing programmers to declare functions that do not throw exceptions, which enhances exception safety by enabling compiler optimizations such as eliding the generation of stack unwinding code in non-throwing paths. This specifier integrates with SFINAE (Substitution Failure Is Not An Error), permitting to select implementations based on whether operations might throw, thus facilitating stronger guarantees in generic code like std::move constructors in containers. If an exception escapes a noexcept function, std::terminate is called immediately, providing predictable failure modes over dynamic exception specifications from prior standards. In C++17, guaranteed copy elision was mandated for certain cases, such as returning local variables or throwing/catching by value, which reduces the number of constructor and destructor calls that could potentially throw, thereby making strong exception guarantees more feasible and performant. further advanced this area with the introduction of s, which require a promise_type::unhandled_exception() method to capture and handle exceptions safely without propagation across suspension boundaries. refined coroutine support with , ensuring exception safety by capturing unhandled exceptions via the promise_type::unhandled_exception() method to prevent propagation across resumption points. As of 2025, the Contracts facility, adopted into the C++26 working paper, introduces preconditions, postconditions, and assertions to verify program states, indirectly bolstering exception safety by allowing customizable violation handlers that can unwind the or ensure invariants without relying solely on termination. Originally proposed for but deferred, Contracts evaluate postconditions on normal returns to support reliable state preservation, with future extensions planned for exception exit checks to further enhance strong guarantees in asynchronous and modular code.

Types of Guarantees

Basic Guarantee

The basic exception safety guarantee is the minimal level of protection provided by an operation in the presence of exceptions, ensuring that if an exception is thrown, the program state remains valid but may be indeterminate, with no resource leaks or data corruption occurring. This guarantee means that all objects involved maintain their invariants, allowing them to be safely accessed or destroyed afterward, and resources such as memory or file handles are properly released. In terms of scope, the basic guarantee covers the commitment or of partial changes during the operation, provided that for involved objects do not throw exceptions themselves, as throwing from can violate this level. It aligns with the general classification framework in the standards, where operations are expected to preserve overall program validity without introducing . However, the basic guarantee has limitations, as it permits partial commitment of changes—such as some objects being modified while others remain unchanged—without requiring a full to the original state, though all class invariants must still hold after the exception. This can result in a program state that is consistent but not identical to the pre-exception condition, potentially requiring additional handling for operations sensitive to partial updates. This guarantee is suitable for operations where achieving a full state restoration would be prohibitively costly in terms of or , such as simple updates to s that can tolerate some inconsistency as long as is preserved.

Strong Guarantee

The strong exception safety guarantee ensures that if an operation throws an exception, the program's remains exactly as it was before the operation began, providing a full with no partial changes or resource leaks. This is stricter than the basic guarantee, which only requires the program to remain in a valid but allows modifications as long as invariants are preserved. In practice, this guarantee is essential for operations like container insertions or assignments where failure must not alter the original . To achieve the strong guarantee, all changes must be reversible, typically through a two-phase approach: first, prepare all modifications in a temporary or isolated context without affecting the original state, then commit them atomically only if no exceptions occur. A common idiom for this is , where a full copy of the target is created using the (which must itself be exception-safe), modifications are applied to the copy, and then the contents are swapped with the original using a noexcept swap function; if an exception arises during modification, the original remains untouched as the copy is discarded. This pattern ensures commit-or-rollback semantics but relies on the providing at least basic safety. In C++11 and later, move semantics significantly aid in providing the strong guarantee more efficiently, particularly for containers like std::vector, by allowing low-cost transfers of resources during reallocation or insertion without unnecessary copies, while noexcept specifications prevent termination on exceptions from moves and restore strong safety for operations that previously risked weakening it. For instance, vector's push_back can now leverage move constructors to attempt in-place growth, falling back to a temporary only if needed, thus minimizing overhead while maintaining rollback on failure. However, implementing the strong guarantee incurs higher performance costs compared to weaker assurances, as it requires additional temporary allocations and potential full copies before committing changes, which can double or triple execution time in resource-intensive operations. It is not always feasible, especially for I/O-bound tasks or those involving external state like file writes or network transmissions, where partial effects (e.g., data sent before failure) cannot be reliably undone without complex compensation mechanisms. In such cases, developers often settle for the basic guarantee to balance safety and efficiency.

No-Throw Guarantee

The no-throw guarantee, also referred to as the nothrow guarantee, represents the strongest form of exception safety in C++, wherein a or destructor pledges to never propagate an exception, regardless of internal errors or exceptional conditions. Instead, any failures are communicated through non-exceptional means, such as return values, error codes, or assertions, ensuring the operation either completes successfully or fails predictably without disrupting the program's exception-handling flow. This is distinct from weaker assurances, as it eliminates the possibility of exceptions entirely, thereby preventing leaks or that could arise from unhandled throws. In practice, the no-throw guarantee is essential for specific operations like and swap functions, where throwing exceptions could lead to or program termination. in C++11 and subsequent standards are implicitly declared noexcept(true), meaning they must not throw; violating this results in std::terminate() being called if an exception escapes. Similarly, std::swap for standard containers, such as std::vector and std::list, provides this guarantee by exchanging internal representations without copying elements, which avoids potential allocation failures that could trigger exceptions. The noexcept specifier, introduced in C++11, explicitly marks functions as non-throwing, superseding deprecated dynamic exception specifications and enabling compile-time verification of safety contracts. This guarantee yields key benefits by facilitating optimizations and enhancing reliability in exception-aware designs. Compilers can omit exception-handling overhead, such as unwinding , in noexcept functions, leading to faster execution in performance-critical paths like move constructors, which often rely on no-throw swaps for efficiency. It also streamlines caller by removing the need for surrounding try-catch blocks and ensures adherence to the library's requirements, where post-C++11 components like move semantics demand no-throw behavior to maintain overall exception safety without compromising usability. For instance, containers' assignment operators leverage no-throw swaps to achieve strong guarantees, underscoring noexcept's role in enabling robust, optimized implementations.

Achieving Exception Safety

Resource Acquisition and Release

Resource Acquisition Is Initialization (RAII) is a fundamental C++ idiom that ties the lifecycle of a resource to the lifetime of an object, ensuring automatic management without explicit intervention. In this approach, resources such as memory or file handles are acquired during the object's constructor and released in its destructor, leveraging the language's deterministic destruction semantics during normal scope exit or exception-induced stack unwinding. This mechanism supports exception safety by guaranteeing resource cleanup even if an exception propagates, preventing leaks that could occur in manual management schemes. For the basic guarantee, RAII ensures that object invariants are maintained and resources are released upon failure, avoiding partial states or dangling references. Under the strong guarantee, it facilitates by automatically reverting acquired resources if an operation throws, restoring the pre-operation state without residual effects. Common resources managed via RAII include dynamic memory allocations, file descriptors, mutex locks, and network sockets, where failure to release them could lead to exhaustion or deadlocks. Scope guards, implemented as objects that perform cleanup actions in their destructors regardless of exit path, provide additional safety for non-RAII-compatible scenarios like early returns or conditional releases. Introduced in C++11, standard smart pointers like std::unique_ptr and std::shared_ptr significantly enhance by providing built-in, exception-safe wrappers for dynamic memory, eliminating common pitfalls in raw pointer usage and promoting safer ownership semantics in modern codebases. Destructors in RAII objects, including those for smart pointers, are required to be non-throwing to avoid terminating the program during unwinding.

Code Patterns and Best Practices

One common pattern for achieving exception safety in constructors is two-phase initialization, where an object is first constructed in a safe default state and then initialized separately, allowing the constructor to provide at least the basic guarantee by avoiding partial initialization if the second phase fails. This approach minimizes the risk of leaving objects in invalid states during resource acquisition, though it requires careful design to maintain invariants post-initialization. The copy-and-swap idiom is a widely used technique for implementing operators that provide , by creating a temporary copy of the right-hand side, performing modifications on the copy (which may throw), and then swapping it with the original object using a non-throwing swap operation; if an exception occurs, the original object remains unchanged. This pattern leverages of the copy constructor and the no-throw of swap to ensure atomicity in modifications. Exception-neutral interfaces design functions and classes to neither suppress nor introduce unexpected exceptions, allowing thrown exceptions to propagate naturally unless explicitly handled, thereby preserving the caller's ability to respond to errors without masking them. A key is to avoid throwing exceptions from , as doing so can lead to program termination during stack unwinding; instead, should either complete normally or call std::terminate() if an error is detected. Declaring as noexcept enforces this behavior and signals to the that no exceptions will escape, enabling optimizations and preventing . Using the noexcept specifier on functions that cannot throw, such as move operations and swap functions, improves exception safety by allowing the to generate more efficient code (e.g., assuming no unwinding in standard library algorithms) and by providing compile-time checks via the noexcept operator to verify guarantees. For instance, standard library containers like provide the strong guarantee for operations such as insert and resize, relying on noexcept move constructors to avoid reallocation failures leaving the container in an inconsistent state. To verify exception safety, developers should test code with simulated exceptions injected at potential failure points, ensuring that invariants hold and resources are released correctly under various throw scenarios, as manual testing alone often misses edge cases. Third-party libraries like Boost.Scope provide scope guards—RAII-based utilities such as scope_exit, scope_success, and scope_fail—that automatically execute cleanup actions on scope exit, with failure variants triggering only on exceptions to support rollback and enhance the basic or strong guarantees without manual try-catch blocks. In modern C++ (post-C++11), practices have evolved to include contracts from C++26 (P2900), which allow precondition, postcondition, and assertion annotations that can be checked at runtime or compile-time to enforce safety invariants, potentially integrating with noexcept for broader exception-neutral designs; attributes like [[nodiscard]] further aid by warning against ignoring values that might signal errors.

Practical Examples

Basic Exception-Safe Function

A simple example of a providing the basic exception guarantee is one that appends two elements to a std::vector. The basic exception guarantee means that if an exception is thrown during execution, the program will be left in a valid state with no resource leaks, though the operation may be only partially completed. Consider the following function:
cpp
#include <vector>

void append_two(std::vector<int>& vec, int a, int b) {
    vec.push_back(a);  // Succeeds, vector size increases by 1
    vec.push_back(b);  // Assume this throws std::bad_alloc due to memory exhaustion
}
In this code, the first push_back(a) operation allocates space and copies the value a into the , increasing its by one and maintaining the container's invariants. If the second push_back(b) throws an exception—such as std::bad_alloc when memory allocation fails—the exception propagates up the call stack without further execution of the function. The std::vector class employs RAII (Resource Acquisition Is Initialization) to manage its internal memory buffer: the buffer is acquired in the constructor or during reallocation in push_back, and automatically released in the destructor if an exception unwinds the . Step by step, upon the throw from push_back(b):
  1. No additional memory is leaked because the vector's partially extended buffer (if reallocation occurred) is rolled back by the container's exception-safe , which destroys any constructed elements and deallocates excess memory.
  2. The vector remains in a valid state, with all previously existing elements intact and the new element a successfully appended.
  3. Destructors for any temporary objects created during the failed push_back(b) are invoked during stack unwinding, ensuring cleanup.
Before the call, suppose the has size n. If the exception occurs, after unwinding the vector's size is n+1, containing the original elements plus a, but without b. This partial modification distinguishes it from the strong , where the state would revert to exactly size n or complete to n+2; here, the valid but altered state exemplifies basic safety without resource leaks.

Transactional Operations with Strong Guarantee

In C++, transactional operations with the strong exception guarantee emulate atomic commit-or-rollback semantics, ensuring that if an exception is thrown during the operation, the program's observable state remains unchanged as if the operation never began. This level of safety is particularly valuable for complex modifications involving multiple state changes, such as updating several related data structures or resources, where partial failure could lead to inconsistent or corrupted states. Unlike the basic guarantee, which only prevents resource leaks and maintains object usability, the strong guarantee restores the pre-operation state fully, including preserving invariants and iterator validity where applicable. Achieving the strong guarantee typically requires isolating potentially exception-throwing work from the main state and using non-throwing mechanisms for final commitment. A common pattern is the copy-and-swap idiom, where the operation is performed on a temporary copy of the affected state, and if successful, the changes are atomically transferred to via a non-throwing swap operation. This approach leverages the strong guarantee of the copy constructor (if it provides one) and ensures simply by letting the temporary destruct without affecting . For instance, in implementing a copy assignment operator for a managing dynamic resources, the creates a copy, modifies it, and swaps only on success. Consider a simplified example of a Widget class using the pimpl idiom with a pointer to implementation details. The copy-and-swap pattern for operator= provides strong safety:
cpp
class Widget {
private:
    std::unique_ptr<WidgetImpl> pImpl;  // RAII-managed resource

public:
    Widget(const Widget& rhs) : pImpl(std::make_unique<WidgetImpl>(*rhs.pImpl)) {}  // Strong guarantee assumed

    Widget& operator=(Widget rhs) {  // Pass by value to create copy
        rhs.swap(*this);  // Non-throwing swap commits changes
        return *this;
    }

    void swap(Widget& other) noexcept {  // No-throw guarantee
        using std::swap;
        swap(pImpl, other.pImpl);
    }
};
Here, if an exception occurs during the implicit copy in operator=, the original Widget remains unmodified; the temporary's destruction handles cleanup without side effects. This pattern extends to broader transactional operations, such as bulk inserts into a container: copy the container, perform insertions on the copy, and swap if all succeed, ensuring the original container is either fully updated or untouched. Performance costs arise from copying, so it's reserved for cases where strong safety outweighs overhead, such as financial or database-like simulations in user code. For multi-object transactions, such as coordinating changes across a vector of widgets, the pattern scales by wrapping the copy-and-modify logic in a scope with RAII helpers, but requires all components to support strong guarantees themselves. Standard library containers like std::vector often provide only basic guarantees for operations like insert to avoid copy overhead, prompting custom wrappers for transactional needs. This design philosophy balances safety with efficiency, as outlined in C++ best practices.

References

  1. [1]
    [PDF] Exception Safety: Concepts and Techniques - Bjarne Stroustrup
    The notion of exception safety is based on the basic guarantee that maintains basic invariants and avoids resource leaks and the strong guarantee that ensures ...
  2. [2]
    Exceptions - cppreference.com - C++ Reference
    If the function throws an exception, the program is in a valid state. No resources are leaked, and all objects' ...
  3. [3]
    How to: Design for exception safety | Microsoft Learn
    Aug 2, 2021 · The strong guarantee states that if a function goes out of scope because of an exception, it will not leak memory and program state will not be ...Basic techniques · The three exception guarantees
  4. [4]
    Exception Safety - D Programming Language
    Exception safe programming is programming so that if any piece of code that might throw an exception does throw an exception, then the state of the program is ...
  5. [5]
  6. [6]
    Modern C++ best practices for exceptions and error handling
    Jun 19, 2025 · An exception forces calling code to recognize an error condition and handle it. Unhandled exceptions stop program execution.
  7. [7]
    [PDF] A History of CLU - CSAIL Publications - MIT
    Dec 6, 1973 · Also, Jim Mitchell described his early work on error handling, which led to the exception handling mechanism in Mesa [Mitchell, 1978].Missing: origins | Show results with:origins
  8. [8]
    Origins of Ada features - ACM Digital Library
    11 Exception handling (a requirement o f. Ironman) is derived from a proposal o f. Bron, Fokkinga and De Haas in 1976. (Reference [BFH76]) . 11 .1 Predefined ...
  9. [9]
    [PDF] reference manual for the ADA programming language
    Copyright 1980, 1982, 1983 owned by the United States Government as ... Exceptions Raised During the Execution of Statements 11-4. 11.4.2 Exceptions ...
  10. [10]
    [PDF] A History of C++: 1979− 1991 - Bjarne Stroustrup
    Jan 1, 1984 · The actual design of the C++ exception mechanism stretched from 1984 to 1989. Andrew. Koenig was closely involved in the later iterations and ...
  11. [11]
    [PDF] Exception Handling for C++ - Bjarne Stroustrup
    This paper outlines a design for an exception handling mechanism for C++. It pre- sents the reasoning behind the major design decisions and considers their ...
  12. [12]
  13. [13]
  14. [14]
    Coroutines (C++20) - cppreference.com
    Mar 5, 2025 · A coroutine is a function that can suspend execution to be resumed later. Coroutines are stackless: they suspend execution by returning to the caller.
  15. [15]
    C++23: Ranges Improvements and std::generator - Modernes C++
    Sep 18, 2023 · C++20 does not provide concrete coroutines, but C++20 provides a framework for implementing coroutines. This changes with C++23.Std::Generator · Std::Ranges::Elements_of · Std::Bind_back<|separator|>
  16. [16]
    [PDF] Contracts for C++ — Rationale - Open Standards
    Mar 14, 2025 · In Phase Four, after the C++2a Contracts proposal had been removed from the C++20 Working. Paper and C++20 shipped without Contracts, renewed ...
  17. [17]
  18. [18]
    GotW #59: Exception-Safe Class Design, Part 1: Copy Assignment
    Strong Guarantee: If an exception is thrown, program state remains unchanged. This level always implies global commit-or-rollback semantics, including that ...<|separator|>
  19. [19]
    P3166R0: Static Exception Specifications - Open Standards
    Mar 17, 2024 · In C++11, we introduced noexcept , initially as a tool needed to restore the strong exception-safety guarantee to types like std::vector after ...
  20. [20]
    What is the "vector pessimization"? – Arthur O'Dwyer
    Aug 26, 2022 · So we have the strong exception guarantee: If push_back throws an exception, then all your data is still there; it's as if the push_back ...
  21. [21]
    Exception-Safety in Generic Components - Boost
    The basic guarantee: that the invariants of the component are preserved, and no resources are leaked. · The strong guarantee: that the operation has either ...
  22. [22]
    [PDF] A brief introduction to C++'s model for type- and resource-safety
    This work was followed up by the integration of resource management and error handling (RAII) [Stroustrup,1994], and eventually with Howard Hinnant's work on ...
  23. [23]
    C++ Core Guidelines - GitHub Pages
    Jul 8, 2025 · The C++ Core Guidelines are a set of tried-and-true guidelines, rules, and best practices about coding in C++.
  24. [24]
    C++11 Standard Library Extensions — General Libraries, C++ FAQ
    The uses of unique_ptr include: providing exception safety for dynamically allocated memory; passing ownership of dynamically allocated memory to a function ...
  25. [25]
    [PDF] Copy-Swap Helper - Open Standards
    Feb 12, 2016 · is often called the strong guarantee of exception safety. In pseudo-C++, the copy-swap idiom for safely modifying an object x of type T is:.
  26. [26]
  27. [27]
  28. [28]
    Scope guards
    ### Summary: How Scope Guards Aid Exception Safety
  29. [29]
    [PDF] Contracts for C++
    Feb 29, 2024 · In this paper, we propose a Contracts facility for C++ that has been carefully considered by SG21 with the highest bar possible for consensus.
  30. [30]
  31. [31]
    GotW #82: Debate #1 - Exception Safety and Specifications
    The strong guarantee involves transactional commit/rollback semantics: failed operations guarantee program state is unchanged with respect to the objects ...
  32. [32]
    What's New in Effective C++? - Scott Meyers
    Scott Meyers' Effective C++ has defined good programming in C++ since ... Approaches to the strong guarantee. Careful statement ordering; Copy and swap.