Daily bit(e) C++. Ограничение noexcept

Добавлено 17 марта 2024 в 23:11

Daily bit(e) 439. Поддержка ограничивающего кода noexcept с помощью концептов C++20.

Daily bit(e) C++

Реализация обобщенного кода C++ может быть сложной, поскольку любая операция потенциально может выкинуть исключение.

Примечательно, что, когда требуется строгая гарантия исключений, это может значительно усложнить код и привести к накладным расходам во время выполнения (или даже к изменению сложности «O большого»).

К счастью, для обеспечения соблюдения гарантий noexcept во время компиляции концепты можно использовать C++20.

#include <utility>

struct UnsafeType 
{
    UnsafeType() = default;
    UnsafeType(UnsafeType&&) {}
    UnsafeType& operator=(UnsafeType&&) { return *this; }
};

template <typename T>
void unsafe_swap(T& left, T& right) 
{
    auto tmp = std::move(left);
    left = std::move(right); // Что будет, если этот move выкинет исключение?
    // было выполнено перемещение значения из left,
    // и перемещение этого значения в right снова может выкинуть исключение
    right = std::move(tmp);
}

struct SafeType 
{
    SafeType() = default;
    SafeType(SafeType&&) noexcept {}
    SafeType& operator=(SafeType&&) noexcept { return *this; }
};

template <typename T>
requires requires (T& a, T& b) 
{
  // присваивание перемещением допустимо и не выкидывает исключение
 { a = std::move(b) } noexcept;
}
void safe_swap(T& left, T& right) 
{
    auto tmp = std::move(left);
    left = std::move(right);
    right = std::move(tmp);
}

SafeType a, b;
safe_swap(a, b); // OK

UnsafeType x, y;
// Не скомпилируется:
// safe_swap(x, y);
// UnsafeType не удовлетворяет требованию noexcept

Пример на Compiler Explorer

Теги

C++ / CppC++20Daily bit(e) C++Концепты C++ / C++ conceptsПрограммирование