简体   繁体   中英

Need clarification about C++ std::iterator

Reading a C++ book I encountered the following example on using iterators:

vector<string::iterator> find_all(string& s, char c)
{
    vector<string::iterator> res;
    for(auto p = s.begin(); p != s.end(); ++p)
        if(*p == c)
            res.push_back(p);
    return res;
}

void test()
{
    string m {"Mary had a little lamb"};
    for(auto p : find_all(m, 'a'))
        if(*p != 'a')
            cerr << "a bug!\n";
}

I'm a little confused about what the vector returned by find_all() contains. Is it essentially "pointers" to the elements of the string m created above it?

Thanks.

Yes, iterators are like pointers. std::string::iterator can even be an alias for char * , although it's usually not.

In general, iterators provide a subset of pointer functionality. Which subset depends on the iterator. Your book probably covers this, but all iterators can be dereferenced ( * , but there is never a reference & operation) and incremented ( ++ ), then some additionally provide -- , and some add + and - on top of that.

In this case, the function seems to assume you will only be querying the values of the iterators without modifying the string. Because the allocation block used for string storage may change as the string grows, iterators (like pointers) into the string may be invalidated. This is why std::string member functions like string::find return index numbers, not iterators.

A vector of indexes could be a better design choice, but this is good enough for an example.

I'm a little confused about what the vector returned by find_all() contains. Is it essentially "pointers" to the elements of the string m created above it?

Mostly; iterators aren't (necessarily) pointers, they are somewhat a generalization of the pointer concept. They are used to point to specific objects stored inside containers (in this case, characters inside a string), you can use them to move between the elements of the string (via the usual arithmetic operators - when they are supported) and you "dereference" them with * to get a reference to the pointed object.

Notice that, depending from the container, they are implemented differently and provide different features; an iterator to a std::list , for example, will allow ++ , -- and *, but not moving to arbitrary locations, and an iterator to a singly-linked list won't even support -- , while typically iterators to array-like data structures (like vector or string ) will allow completely free movement.

To refer to elements in array-like structures often one just stores indexes, since they are cheap to store and use; for other structures, instead, storing iterators may be more convenient.

For example, just yesterday I had some code which walked a unordered_set<string, int> (=a hashtable that mapped some words to their occurrences) to "take note" of some of the (string, int) couples to use them later.

The equivalent of storing vector indexes here would have been storing the hashtable's keys, but (1) they are strings (so they are moderately costly to allocate and handle), and (2) to use them to reach the corresponding object I had to do another hashtable lookup later. Instead, storing iterators in a vector guarantees no hassle for storing strings (iterators are intended to be cheap to handle) and no need to perform a lookup again.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM