Bantak
Bantak

Reputation: 638

Use nullptr instead of end iterator

I would like to know if it is possible to use nullptr or some kind of generic end iterator.

For example:

// a.b->cdef().g->bdf() is a std::map<int, int>
std::unordered_map<int, int> copy(a.b->cdef().g->bdf().begin(), a.b->cdef().g->bdf().end());

is what you would normally write to specify the begin and end to initialize the new map.

Why do I need to specify the end tag if I just want to copy the whole map.

I would prefer something like:

std::unordered_map<int, int> copy(a.b->cdef().g->bdf().begin(), nullptr);

or

std::unordered_map<int, int> copy(a.b->cdef().g->bdf().begin());

or

std::unordered_map<int, int> copy(a.b->cdef().g->bdf().begin(), std::unordered_map::end);

edit: I changed the example from a std::list<int> to a std::unordered_map<int, int>. There is no copy constructor from std::map to std::unordered_map.

Upvotes: 0

Views: 2725

Answers (3)

Peter
Peter

Reputation: 36597

Copying of ranges in the STL is mostly specified using a pair of iterators. This is because most copying operations need to be finite, and it is hard to specify a finite range using a single iterator.

nullptr is not an iterator that any standard container will return, and does not provide an alternative.

Alternatives include adding a helper function that accepts containers as arguments (preferably by reference). Then it is possible to extract iterators from those containers with less fuss.

The best option is almost certainly to improve your basic design and coding technique to avoid the need for code to explicitly dig down through an excessive number of nested structs to find data (e.g. a.b->cdef().g->bdf()). Simple and readable code is easier to understand and therefore easier to get right.

Upvotes: 1

Zan Lynx
Zan Lynx

Reputation: 54325

To answer the question asked, "Is it possible to use nullptr instead of end()?"

No.

Please think about how the containers and iterators are implemented. A container knows its begin and end iterators. An iterator knows how to increment, decrement and compare itself to another iterator.

So take a vector for example. How does the begin iterator know where to stop incrementing? How would iter == nullptr know when to return true so it could stop?

Or take a circular linked list. It has no real end. It only stops when an iterator equals the begin iterator again. What would nullptr even mean as an end there?

If you think about the implementation you'll see why the answer is "No."

Upvotes: 5

juanchopanza
juanchopanza

Reputation: 227390

If you want to copy the contents of a whole container into a container of a different type you can use a helper function

template<typename InputIterRange, typename OutputIter>
OutputIter range_copy(InputIterRange&& range, OutputIter out_iter)
{
  return std::copy(range.begin(), range.end(), out_iter);
}

This works as long as the value_types of each container are convertible to each other. Example use:

int main() {
    std::set<int> a{1,2,3,4,5};
    std::unordered_set<int> b {11,22,33};
    range_copy(a, std::inserter(b, b.end()));
}

Upvotes: 1

Related Questions