The University of Iowa
The College of Liberal Arts and Sciences
Department of Computer Science
Lecture/Lab #22
Strict weak ordering, iterators
struct organism {
organism( point const& pos )
: pos_( pos ) {}
point position() const { return pos_; }
private:
point pos_;
};
Given the following definition of class `organism`:
... what data structure would you use to represent a list of the organisms populating a rectangular map, assuming that only one organism can occupy a specific position?
By default std::map/set elements are ordered using std::less predicate, which forwards to operator <.
We can provide our own comparison criteria:
set<student, compare_email> class_roster;
The specified comparison function must induce a strict weak ordering on the container's keys.
(1, 1)
(2, 3)
X
Y
A binary relation that we'll name < that has the following properties:
Irreflexive: it's never the case that a < a;
Asymmetric: if a < b, then it's never the case that b < a;
Transitive: if a < b and b < c, then it's always the case that a < c;
Transitively incomparable: if a is incomparable with b (neither a < b nor b < a hold), and b is incomparable with c, then it's always the case that a is incomparable with c.
bool operator<( point const& l, point const& r )
{
return l.x < r.x && l.y < r.y;
}
Does our `operator<` satisfy these requirements?
What happens if our `operator <` fails to satisfy these requirements?
Nothing — as long as users of our type don't try to use it as a key in one of the standard ordered associative containers
Otherwise undefined behavior — with consequences ranging from unexpected results to run-time crashes.
bool operator<( point const& l, point const& r )
{
return std::pair( l.x, l.y ) < std::pair( r.x, r.y );
}
How to write `operator<` that imposes strict weak ordering on point objects
For any type that can conceivably be placed in std::set or used as a key in std::map, operator< has two jobs:
Define a relation that makes intuitive sense for users of the type (if ( a < b ) ...);
Define a relation that imposes a strict weak ordering on objects of the type, so that it can be safely used in ordered associative containers.
These two distinct jobs of the operator< — providing a natural "less than" relation that makes sense in the class' domain vs. defining an ordering of the class' objects for the standard library — can sometimes be at odds with each other.
Guideline
If your class provides an operator< that does not satisfy strict weak ordering requirements, make sure to also specialize std::less with an implementation that does.
Objects with a well-defined interface that enable us to iterate/traverse over elements of a container without knowing the container's underlaying data structure.
In C++, the standard iterator interface is that of a generalized pointer.
std::vector<student> roster1 = { ... };
std::set<student> roster2 = { ... };
for ( auto const& s: roster1 )
std::cout << s << "\n";
for ( auto const& s: roster2 )
std::cout << s << "\n";
for ( auto const& s: roster1 )
std::cout << s << std::endl;
{
auto iter = roster1.begin();
auto end = roster1.end();
for ( ; iter != end; ++iter )
std::cout << *iter << std::endl;
}
[ begin, end )
— half-open interval aka inclusive/exclusive range
v.end()
v.begin()
...
Obtaining an iterator to the beginning of a sequence:
Moving forward in a sequence:
Recognizing an end of a sequence:
begin( seq )
++i
i != end( seq )
Accessing the element:
*i
Moving backward in a sequence:
--i
Advance to an nth element (O(1) arithmetics):
i += n, i + n, i -= n, i - n, i - j
Compare iterator position:
i < j, i <= j, i > j, i >= j
any
any
any
any
bidirectional
random access
random access
Iterator category
people = set([ "jack", "sape" ])
for k in people:
print(k)
print("-------------------")
iterator = people.__iter__()
while True:
try:
item = iterator.__next__()
print(item)
except StopIteration:
break
set<string> people{ "jack", "sape" };
for ( auto k : people )
std::cout << k << "\n";
std::cout << "-----------------\n";
auto iter = people.begin();
auto end = people.end();
for ( ; iter != end; ++iter )
std::cout << *iter << "\n";
Write a function `find` that takes a vector of strings and a string value to search for and returns an iterator to the matching vector element
Open the exercise template
Write your code, press Run to test
When you're done, grab your Repl's link and send it as a direct message to me (agurtovoy)
Click on the corresponding option in the "Lab22 exercises" poll in #general