This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of New status.

4431. Parallel std::ranges::destroy should allow exceptions

Section: 20.2.2 [memory.syn] Status: New Submitter: Ruslan Arutyunyan Opened: 2025-10-24 Last modified: 2025-10-25

Priority: Not Prioritized

View all other issues in [memory.syn].

View all issues with New status.

Discussion:

The serial std::ranges::destroy algorithm is marked as noexcept. However, the parallel counterpart should not be marked noexcept.

While we generally don't expect any exceptions from the destroy algorithm when called with the standard execution policies (seq, unseq, par, par_unseq), the implementation-defined policies for parallel algorithms are allowed by the C++ standard, and it is up to the particular execution policy to decide which exceptions can be thrown from parallel algorithms.

Proposed resolution:

This wording is relative to N5014.

  1. Modify 20.2.2 [memory.syn], header <memory> synopsis, as indicated:

    [Drafting note: There are no further prototype definitions for the affected execution-policy overloads in 26.11.9 [specialized.destroy].]

    […]
    // 26.11.9, 26.11.9 [specialized.destroy]
    template<class T>
      constexpr void destroy_at(T* location);                                  // freestanding
    template<class NoThrowForwardIterator>
      constexpr void destroy(NoThrowForwardIterator first,                     // freestanding
                             NoThrowForwardIterator last);
    template<class ExecutionPolicy, class NoThrowForwardIterator>
      void destroy(ExecutionPolicy&& exec,                                     // freestanding-deleted,
                   NoThrowForwardIterator first,                               // see 26.3.5 [algorithms.parallel.overloads]
                   NoThrowForwardIterator last);
    template<class NoThrowForwardIterator, class Size>
      constexpr NoThrowForwardIterator destroy_n(NoThrowForwardIterator first, // freestanding
                                                 Size n);
    template<class ExecutionPolicy, class NoThrowForwardIterator, class Size>
      NoThrowForwardIterator destroy_n(ExecutionPolicy&& exec,                 // freestanding-deleted,
                                       NoThrowForwardIterator first, Size n);  // see 26.3.5 [algorithms.parallel.overloads]
    namespace ranges {
      template<destructible T>
        constexpr void destroy_at(T* location) noexcept;                       // freestanding
        
      template<nothrow-input-iterator I, nothrow-sentinel-for <I> S>
        requires destructible<iter_value_t<I>>
          constexpr I destroy(I first, S last) noexcept;                       // freestanding     
      template<nothrow-input-range R>
        requires destructible<range_value_t<R>>
          constexpr borrowed_iterator_t<R> destroy(R&& r) noexcept;            // freestanding
          
      template<nothrow-input-iterator I>
        requires destructible<iter_value_t<I>>
        constexpr I destroy_n(I first, iter_difference_t<I> n) noexcept;       // freestanding
        
      template<execution-policy Ep, nothrow-random-access-iterator I,
               nothrow-sized-sentinel-for <I> S>
        requires destructible<iter_value_t<I>>
          I destroy(Ep&& exec, I first, S last) noexcept;                       // freestanding-deleted,
                                                                                // see 26.3.5 [algorithms.parallel.overloads]
      template<execution-policy Ep, nothrow-sized-random-access-range R>
        requires destructible<range_value_t<R>>
          borrowed_iterator_t<R> destroy(Ep&& exec, R&& r) noexcept;            // freestanding-deleted,
                                                                                // see 26.3.5 [algorithms.parallel.overloads]
      template<execution-policy Ep, nothrow-random-access-iterator I>
        requires destructible<iter_value_t<I>>
          I destroy_n(Ep&& exec, I first, iter_difference_t<I> n) noexcept;     // freestanding-deleted,
                                                                                // see 26.3.5 [algorithms.parallel.overloads]
    }
    […]