Skip to content

SmallVector: Exception safety #75

@jsrivaya

Description

@jsrivaya

Parent

Part of #5. Depends on #71, #72, #74.

Summary

Audit and enforce exception safety guarantees across all SmallVector operations, with specific handling for the heap transition — the most dangerous point for correctness.

Guarantees to provide

Operation Guarantee
push_back / emplace_back Strong — if T's ctor throws, SmallVector unchanged
insert / emplace Strong if no reallocation; Basic if reallocation needed
erase No-throw if T's move/dtor is no-throw
reserve Strong — old storage untouched until move succeeds
Heap transition Strong — allocate new block, move all elements, then destroy old
Copy constructor Strong
Move constructor No-throw for heap mode; Basic for inline mode if T's move throws

The heap transition in detail

This is the riskiest operation:

void grow() {
    size_t new_cap = capacity_ * 2;
    T* new_heap = static_cast<T*>(::operator new(new_cap * sizeof(T)));

    // Move elements — if any move throws, we must clean up new_heap
    size_t moved = 0;
    try {
        for (; moved < size_; ++moved)
            new(new_heap + moved) T(std::move(data()[moved]));
    } catch (...) {
        // Destroy successfully moved elements
        for (size_t i = 0; i < moved; ++i)
            new_heap[i].~T();
        ::operator delete(new_heap);
        throw;  // re-throw, original storage untouched
    }

    // Destroy originals and switch to heap
    for (size_t i = 0; i < size_; ++i)
        data()[i].~T();
    if (!is_small()) ::operator delete(heap_ptr);
    heap_ptr = new_heap;
    capacity_ = new_cap;
}

If T's move constructor is noexcept, the try/catch can be skipped entirely (compiler will optimise this with if constexpr (std::is_nothrow_move_constructible_v<T>)).

Testing requirements

  • Push into a type whose copy constructor throws on the Nth call — SmallVector must be unchanged
  • Heap transition with a throwing move type — old data preserved
  • Verify noexcept propagation: push_back is noexcept when T's move is noexcept

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions