What is the official behavior for std::vector range constructor when the first itr comes after the last?

StackOverflow https://stackoverflow.com/questions/21786970

  •  11-10-2022
  •  | 
  •  

Pergunta

Assuming you have a valid starting point:

std::vector<UINT32> host = {1,2,3,4,5};

When you try to construct another vector using iterators:

std::vector<UINT32> client(host.begin(),host.end());

// client.size() is 5. Elements begin -> end look just like host.

But what happens if the iterators are backwards? What if the start is after the end?

std::vector<UINT32> backwardsClient(host.end(), host.begin());

// What happens?
Foi útil?

Solução

It will be undefined behavior.

Looking at the Standard:

N3690 23.3.7.2[vector.cons]

template <class InputIterator>
    vector(InputIterator first, InputIterator last,
    const Allocator& = Allocator());

9. Effects: Constructs a vector equal to the range [first,last), using the specified allocator.

It says that the range has to be [first, last), but the standard doesn't mention what happens if that isn't the case. It therefore is undefined behavior.

Outras dicas

The behaviour is undefined. The requirements for this constructor are specified in C++11 [sequence.reqmts]§3+4:

3 In Tables 100 and 101, X denotes a sequence container class, a denotes a value of X containing elements of type T, ... , i and j denote iterators satisfying input iterator requirements and refer to elements implicitly convertible to value_type, [i, j) denotes a valid range, ...

(emphasis mine)

§4 is then Table 100, which defines what X a(i, j) does.

In other words, it's only defined if [i, j) is a valid range, which in your case it's not. So the behaviour is not defined.

First we visit 24.2.1/7 to learn what a valid range is:

Range [i,j) is valid if and only if j is reachable from i. The result of the application of functions in the library to invalid ranges is undefined.

Then it's a simple matter to look up the vector constructor in sequence container requirements 23.2.3/table 100, noting that it requires an iterator range, that from the previous section must be valid. This means that in the example provided you have indefined behavior.

I would say that this would result in undefined behavior.

According to http://cppreference.com, vector::vector(first, last) takes an input iterator, and, regarding iteration, this category of iterators are only required to provide operator!= and operator++.

The vector constructor will basically run a loop equivalent to:

while (first != last) {
    push_back(*first);
    ++first;
}

This will cause an infinite loop, but might be guarded by your standard library implementation by some assertion (at least in debug builds).

According to http://www.cplusplus.com/reference/vector/vector/vector/:

(3) range constructor Constructs a container with as many elements as the range [first,last), with each element constructed from its corresponding element in that range, in the same order.

first, last

Input iterators to the initial and final positions in a range. The range used is [first,last), which includes all the elements between first and last, including the element pointed by first but not the element pointed by last.

In your case, the range [host.end(), host.begin()) will try to include the element pointed by host.end(), and this will generate an error while de-referencing the past-end-iterator.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top