Daniel McIntosh
Daniel McIntosh

Reputation: 575

c++ std::vector iterator constructor with first == last

I have a function which needs to divide a vector up into n sub-vectors. For example, it might look something like this:

void foo(std::vector<uint8_t> vec, int numSubVectors){
    size_t size = vec.size() / numSubVectors;
    auto iter = vec.begin();
    for (int i = 0; i < numSubVectors; ++i) {
        auto sub_vec = std::vector<uint8_t>(iter, iter + size);
        // do something with sub_vec
        // ...

        iter += size;
    }
}

I need this to work when called with foo({}, 1), where sub_vec gets assigned an empty vector on the first (and only) iteration of the loop. I'm concerned about the std::vector<uint8_t>(iter, iter + size). Does the c++ standard allow a vector to be constructed using its range constructor when first == last?

According to cplusplus.com, "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", but that statement doesn't make any sense when first == last?

I tried running it on an online IDE and it seems to work (https://ideone.com/V9hylA), so it's clearly not prohibited, but is it undefined behaviour?

Upvotes: 1

Views: 2107

Answers (2)

user1111122
user1111122

Reputation: 81

From iterator.requirements.general of the standard:

An iterator and a sentinel denoting a range are comparable. A range [i, s) is empty if i == s; otherwise [...]

So when first == last, the standard explicitly defines this as an empty range.

Upvotes: 3

Blastfurnace
Blastfurnace

Reputation: 18652

The iterator pair [first, last) where first == last is how we define an empty range. It's syntactically and logically valid. Constructing a std::vector from that iterator pair will do the correct thing and create an empty container.

Upvotes: 2

Related Questions