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

### 2180. Exceptions from `std::seed_seq` operations

Section: 28.5.8.1 [rand.util.seedseq] Status: C++14 Submitter: Daniel Krügler Opened: 2012-08-18 Last modified: 2016-01-28

Priority: Not Prioritized

View all other issues in [rand.util.seedseq].

View all issues with C++14 status.

Discussion:

28.5.8.1 [rand.util.seedseq] p1 says upfront:

> No function described in this section 28.5.8.1 [rand.util.seedseq] throws an exception.

This constraint seems non-implementable to me when looking especially at the members

>     template<class T>
>     seed_seq(initializer_list<T> il);

>     template<class InputIterator>
>     seed_seq(InputIterator begin, InputIterator end);

which have the effect of invoking `v.push_back()` for the exposition-only member of type `std::vector` (or its equivalent) over all elements of the provided range, so out-of-memory exceptions are always possible and the `seed_seq` object doesn't seem to be constructible this way.

In addition to the potential lack-of-resources problem, the operations of `InputIterator` might also throw exceptions.

Aside to that it should me mentioned, that a default constructor of `vector<uint_least32_t>` in theory can also throw exceptions, even though this seems less of a problem to me in this context, because such an implementation could easily use a different internal container in `seed_seq` that can hold this no-throw exception guarantee.

Secondly, a slightly different problem category related to exceptions occurs for the member templates

>     template<class RandomAccessIterator>
>     void generate(RandomAccessIterator begin, RandomAccessIterator end);

>     template<class OutputIterator>
>     void param(OutputIterator dest) const;

where the actual operations performed by the implementation would never need to throw, but since they invoke operations of a user-provided customization point, the overall operation, like for example

>     copy(v.begin(), v.end(), dest);

could also throw exceptions. In this particular example we can just think of a `std::back_insert_iterator` applied to a container that needs to allocate its elements used as the type for `OutputIterator`.

Even though Clause 28 [numerics] has mostly stronger exception constraints than other parts of the library the here discussed are overrestrictive, especially since no operation of `std::seed_seq` except the template `generate` is actually needed within the library implementation, as mentioned in the discussion of LWG 2124.

I suggest to remove the general no-exception constraints for operations of `std::seed_seq` except for member `size()` and the default constructor and to provide specific wording for `generate()` and `param()` to ensure that the algorithm itself is a nothrow operation, which is especially for `generate()` important, because the templates specified in 28.5.4 [rand.eng] and 28.5.5 [rand.adapt] also depend on this property indirectly, which is further discussed in LWG 2181.

Howard:

I suggest to use a different form for the exception specification, something similar to 22.10.15.4 [func.bind.bind] p4:

> Throws: Nothing unless an operation on `RandomAccessIterator` throws an exception.

Daniel:

The currently suggested "what and when" form seems a bit more specific and harmonizes with the form used for function template `generate_canonical` from 28.5.8.2 [rand.util.canonical].

[2013-04-20, Bristol]

Open an editorial issue on the exception wording ("Throws: What and when").

Solution: move to tentatively ready.

[2013-09-29, Chicago]

Apply to Working Paper

Proposed resolution:

This wording is relative to N3376.

1. Edit 28.5.8.1 [rand.util.seedseq] p1 as indicated:

   > -1- No function described in this section 28.5.8.1 [rand.util.seedseq] throws an exception.

2. Edit 28.5.8.1 [rand.util.seedseq] around p2 as indicated:

   >     seed_seq();

   > > -2- Effects: Constructs a `seed_seq` object as if by default-constructing its member `v`.

   > > -?- Throws: Nothing.

3. Edit 28.5.8.1 [rand.util.seedseq] around p7 as indicated:

   >     template<class RandomAccessIterator>
   >       void generate(RandomAccessIterator begin, RandomAccessIterator end);

   > > -7- Requires: `RandomAccessIterator` shall meet the requirements of a mutable random access iterator (Table 111) type. Moreover, `iterator_traits<class RandomAccessIterator>::value_type` shall denote an unsigned integer type capable of accommodating 32-bit quantities.

   > > -8- Effects: Does nothing if `begin == end`. Otherwise, with `s = v.size()` and `n = end - begin`, fills the supplied range `[begin, end)` according to the following algorithm […]

   > > -?- Throws: What and when `RandomAccessIterator` operations of `begin` and `end` throw.

4. Edit 28.5.8.1 [rand.util.seedseq] around p9 as indicated:

   >     size_t size() const;

   > > -9- Returns: The number of 32-bit units that would be returned by a call to `param()`.

   > > -??- Throws: Nothing.

   > > -10- Complexity: constant time.

5. Edit 28.5.8.1 [rand.util.seedseq] around p11 as indicated:

   >     template<class OutputIterator>
   >       void param(OutputIterator dest) const;

   > > -11- Requires: `OutputIterator` shall satisfy the requirements of an output iterator (Table 108) type. Moreover, the expression `*dest = rt` shall be valid for a value `rt` of type `result_type`.

   > > -12- Effects: Copies the sequence of prepared 32-bit units to the given destination, as if by executing the following statement:

   > > >     copy(v.begin(), v.end(), dest);

   > > -??- Throws: What and when `OutputIterator` operations of `dest` throw.