Is it!=container.end() design mistake/feature or just necessity?

爱⌒轻易说出口 提交于 2021-01-28 23:32:16

问题


recently I was thinking about how it would be nice if iterators implicitly converted to bool so you could do

auto it = find(begin(x),end(x), 42);
if (it)  //not it!=x.end();
{
}

but thinking about it I realized that this would mean that either it would had to be set to "NULL", so that you couldnt use the it directly if you want to do something with it (you would have to use x.end()) or you could use it but iter size would have to be bigger(to store if what it points to was .end() or not). So my questions are:

  1. Is the syntax in my example achievable without breaking current code and without increasing the sizeof iterator?
  2. would implicitly conversion to bool cause some problems?

回答1:


You are working on the assumption that iterators are a way of accessing a container. They allow you to do that, but they also allow many more things that would clearly not fit your intended operations:

auto it = std::find(std::begin(x), std::next(std::begin(x),10), 42 );
    // Is 42 among the first 10 elements of 'x'?

auto it = std::find(std::istream_iterator<int>(std::cout),
                    std::istream_iterator<int>(), 42 );
    // Is 42 one of the numbers from standard input?

In the first case the iterator does refer to a container, but the range where you are finding does not enclose the whole container, so it cannot be tested against end(x). In the second case there is no container at all.

Note that an efficient implementation of an iterator for many containers holds just a pointer, so any other state would increase the size of the iterator.

Regarding conversions to any-type or bool, they do cause many problems, but they can be circumvented in C++11 by means of explicit conversions, or in C++03 by using the safe-bool idiom.

You are probably more interested on a different concept: ranges. There are multiple approaches to ranges, so it is not so clear what the precise semantics should be. The first two that come to mind are Boost.Iterator and an article by Alexandrescu I read recently called On Iteration.




回答2:


Two reasons this wouldn't work:

First, it's possible to use raw pointers as iterators (usually into an array):

int data[] = { 50, 42, 37, 5 };
auto it = find(begin(data), end(data), 42);

Second, you don't have to pass the actual end of the container to find; to e.g. find the first space character before a period:

auto sentence = "Hello, world.";
auto it1 = find(begin(sentence), end(sentence), '.');
auto it2 = find(begin(sentence), it1, ' ');



回答3:


There's very little that can be done with a single iterator. A pair of iterators defines a sequence consisting of the elements; the first iterator points to the first element and the second iterator points one past the end of the last element. There's no way, in general, for the first iterator to know when it's been incremented to match the second iterator. Algorithms do that, because they have both iterators and can tell when the work is done. For example:

std::vector<int> vec;
vec.push_back(1);
vec.push_back(2);
vec.push_back(3);

// copy the contents of the vector:
std::copy(somewhere, vec.begin(), vec.end());
// copy the first two elements of the vector:
std::copy(somewhere, vec.begin(), vec.begin() + 2);

In both calls to copy, vec.begin() is the same iterator; the algorithm does different things because it got the second iterator that tells it when to stop.

Granted, it's possible to design a different kind of iterator that contains both the beginning and the end of the sequence (as Java does), but that's not how C++ iterators are designed. There's discussion of standardizing the notion of a "range" that holds two iterators (the new range-based for loop is a first step toward that).




回答4:


Well, you probably don't want an implicit conversion, but requiring two separate objects to determine when iteration is done is clearly a design error. It's not so much because of the if or the for (although using a single iterator would make these clearer as well); it's really because it makes functional decomposition and filtering iterators extreamly difficult, if not impossible.

Fundamentally, STL iterators are closer to smart pointers than they are to iterators. There are times when such pointers are appropriate, but they aren't a good replacement for iterators.



来源:https://stackoverflow.com/questions/12749899/is-it-container-end-design-mistake-feature-or-just-necessity

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!