624. valarray assignment and arrays of unequal length

Section: 29.7.2.3 [valarray.assign] Status: CD1 Submitter: Martin Sebor Opened: 2007-01-20 Last modified: 2016-02-10

Priority: Not Prioritized

View all other issues in [valarray.assign].

View all issues with CD1 status.

Discussion:

The behavior of the valarray copy assignment operator is defined only when both sides have the same number of elements and the spec is explicit about assignments of arrays of unequal lengths having undefined behavior.

However, the generalized subscripting assignment operators overloaded on slice_array et al (29.7.2.3 [valarray.assign]) don't have any such restriction, leading the reader to believe that the behavior of these overloads is well defined regardless of the lengths of the arguments.

For example, based on the reading of the spec the behavior of the snippet below can be expected to be well-defined:

    const std::slice from_0_to_3 (0, 3, 1);   // refers to elements 0, 1, 2
    const std::valarray<int> a (1, 3);        // a = { 1, 1, 1 }
    std::valarray<int>       b (2, 4);        // b = { 2, 2, 2, 2 }

    b = a [from_0_to_3];
        

In practice, b may end up being { 1, 1, 1 }, { 1, 1, 1, 2 }, or anything else, indicating that existing implementations vary.

Quoting from Section 3.4, Assignment operators, of Al Vermeulen's Proposal for Standard C++ Array Classes (see c++std-lib-704; N0308):

...if the size of the array on the right hand side of the equal sign differs from the size of the array on the left, a run time error occurs. How this error is handled is implementation dependent; for compilers which support it, throwing an exception would be reasonable.

And see more history in N0280.

It has been argued in discussions on the committee's reflector that the semantics of all valarray assignment operators should be permitted to be undefined unless the length of the arrays being assigned is the same as the length of the one being assigned from. See the thread starting at c++std-lib-17786.

In order to reflect such views, the standard must specify that the size of the array referred to by the argument of the assignment must match the size of the array under assignment, for example by adding a Requires clause to 29.7.2.3 [valarray.assign] as follows:

Requires: The length of the array to which the argument refers equals size().

Note that it's far from clear that such leeway is necessary in order to implement valarray efficiently.

Proposed resolution:

Insert new paragraph into 29.7.2.3 [valarray.assign]:

valarray<T>& operator=(const slice_array<T>&); 
valarray<T>& operator=(const gslice_array<T>&); 
valarray<T>& operator=(const mask_array<T>&); 
valarray<T>& operator=(const indirect_array<T>&);

Requires: The length of the array to which the argument refers equals size().

These operators allow the results of a generalized subscripting operation to be assigned directly to a valarray.