How to Iterate Std::Set

How to iterate std::set?

You must dereference the iterator in order to retrieve the member of your set.

std::set<unsigned long>::iterator it;
for (it = SERVER_IPS.begin(); it != SERVER_IPS.end(); ++it) {
u_long f = *it; // Note the "*" here
}

If you have C++11 features, you can use a range-based for loop:

for(auto f : SERVER_IPS) {
// use f here
}

How to iterate through all elements of set C++

addStudent takes a pointer, while it is an iterator, so can't be passed directly.

You should change addStudent to take either a value or a pointer/reference to const:

// option 1
void addStudent(Student);
addStudent(*it);

// option 2
void addStudent(Student const &);
addStudent(*it);

// option 3
void addStudent(Student const *);
addStudent(&*it);

If, as you say in a comment, you must leave it taking a mutable pointer, then you'll need some grotesquery to deal with the fact that elements of the set are immutable:

// nasty option
addStudent(const_cast<Student*>(&*it));

// slightly less nasty option
Student copy = *it;
addStudent(©);

Beware that the first option will give undefined behaviour if the function uses the dodgy pointer to make any modification to the Student object stored in the set. The second makes a temporary copy, which can be modified without breaking the set. This is fine as long as addStudent only stores a copy of the object passed to it, not the pointer itself, which will become invalid when copy is destroyed.

How to iterate over a specific range of std::set/std::multiset?

You cannot do set.begin()+a, but you can do std::advance(it, a):

#include <iostream>
#include <set>
#include <string>

int main()
{
std::set<std::string> set={ "aaa", "bbb", "ccc", "ddd", "eee", "fff" };
size_t a = 1, b = 4;
auto it = set.begin(), it_end = set.begin();
std::advance(it, a);
std::advance(it_end, b);
for(; it!= it_end; ++it)
std::cout << *it << " ";
}

Unfortunately you cannot do something like auto it = std::advance(set.begin(), a);, because advance gets the iterator by reference and changes it inplace.

https://ideone.com/8nRjgr

Better solution use std::next, thanks to @Evg:

#include <iostream>
#include <set>
#include <string>

int main()
{
std::set<std::string> set={ "aaa", "bbb", "ccc", "ddd", "eee", "fff" };
size_t a = 1, b = 4;
for(auto it = std::next(set.begin(), a), it_end = std::next(it, b-a); it != it_end; ++it)
std::cout << *it << " ";
}

https://ideone.com/6wgpMZ

How to iterate std::set based on offset from set.begin()?

I need to get to the iterator having offset ofst: it + ofst: is there
a way to do that?

No, there is no operator+ overload defined for this for std::set::iterator (aka bidirectional iterators). However, you can use std::next, from <iterator> header as follows to achive the same.

#include <iterator>  // std::next

auto nthIter = std::next(it, ofst);

This basically behind the scene increments ofst times too.

The std::set has bidirectional iterators, which has no luxuries like random access iterators, and hence need to increment like this.


That being said, you could overload the operator+(and maybe operator-) for the bidirectional iterators, which will not be recommended though.

std::set iterating over all pairs

it1 + 1 is a random access operation, so it requires the iterator to be a random access iterator, and since std::set<int>::iterator is not a random access iterator, it does not support this operation.

++it2 requires that the iterator is a forward iterator, and since std::set<int>::iterator is a bidirectional iterator, it is a forward iterator.

How iterating over a std::set returns sorted results

We can find a definitive answer by looking at the source code (libstdc++ 5.2.1 in this case). This is how a tree node looks like:

// <libstdc++>/include/bits/stl_tree.h
struct _Rb_tree_node_base {
typedef _Rb_tree_node_base* _Base_ptr;

_Rb_tree_color _M_color;
_Base_ptr _M_parent;
_Base_ptr _M_left;
_Base_ptr _M_right;

// ...
}

So every node contains a color, and pointers to its parent and its left and right children. Incrementing is implemented as:

//  <libstdc++>/include/bits/stl_tree.h
struct _Rb_tree_iterator {
_Self& operator++() {
_M_node = _Rb_tree_increment(_M_node);
return *this;
}

// ...

private:
_Base_ptr _M_node;
};

The actual increment is not in the public headers anymore, but in the compiled part of the library:

// <libstdc++>/src/c++98/tree.cc
static _Rb_tree_node_base* local_Rb_tree_increment(_Rb_tree_node_base* __x) throw ()
{
if (__x->_M_right != 0) {
__x = __x->_M_right;
while (__x->_M_left != 0)
__x = __x->_M_left;
} else {
_Rb_tree_node_base* __y = __x->_M_parent;
while (__x == __y->_M_right) {
__x = __y;
__y = __y->_M_parent;
}
if (__x->_M_right != __y)
__x = __y;
}
return __x;
}

So, ultimately, it's a textbook implementation of tree traversal: The iterator holds a pointer to the "current" node, and to get to the next node it goes up in the tree as long as it was coming from the right child. If it was coming from the left child, it will descend to leftmost child node of the right child.

how to iterate through a set of sets C++

I would do it this way:

 // Iterate through and print output
set < set <string> >::iterator it_ex; // iterator for the "outer" structure
set <string>::iterator it_in; // iterator for the "inner" structure

for(it_ex = Triplets.begin(); it_ex != Triplets.end(); it_ex++)
{
for(it_in = it_ex->begin(); it_in != it_ex->end(); it_in++)
cout << *it_in << ", ";
cout << endl;
}

Why is iterating over a std::set so much slower than over a std::vector?

Isn't a set just a structured vector that checks whether each item is unique upon insertion?

No, by far not. These data structures are completely different, and the main distinction here is the memory layout: std::vector puts its element into a contiguous location in memory, while std::set is a node-based container, where every element is separately allocated and resides at distinct places in memory, possibly far away from each other and definitely in a way that pre-fetching data for fast traversal is impossible for the processor. This is quite the opposite for std::vector - as the next element is always just right "next to" the current one in memory, a CPU will load elements into its cache, and when actually processing the elements, it only has to go to the cache to retrieve the values - which is very fast compared to RAM access.

Note that it's a common need to have a sorted, unique collection of data that is laid out contiguously in memory, and C++2a or the version thereafter might actually ship with a flat_set, have a look at P1222.

Matt Austern's "Why you shouldn't use set (and what you should use instead)" is an interesting read, too.

How to iterate through a STL set till the second last element?

You may use the following in C++11:

std::set<std::bitset<2501>> arr;
std::set<std::bitset<2501>>::iterator end= arr.end();

for(std::set<std::bitset<2501> >::iterator it1 = arr.begin();it1 != end; ++it1)
{
for(std::set<std::bitset<2501> >::iterator it2 = std::next(it1); it2 != end; ++it2)
{
//do processing, I didn't show the OR operation
}
}


Related Topics



Leave a reply



Submit