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
  •  | 
  •  

質問

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?
役に立ちましたか?

解決

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.

他のヒント

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.

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top