The University of Iowa
The College of Liberal Arts and Sciences
Department of Computer Science
Programming Languages and Tools:
CS:3210:0001
Lecture/Lab #22
Programming with C++
Strict weak ordering, iterators
Warm up
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?
std::map/set Ordering
-
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.
Strict weak ordering
bool operator<( point const& l, point const& r )
{
return l.x < r.x && l.y < r.y;
}
Does our `operator<` satisfy these requirements?
Strict weak ordering (cont.)
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 ) ...);
Strict weak ordering implications
-
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.
Iterators
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";
Iterators (cont.)
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()
...
Iterator Operations
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
C++ vs Python's iterators
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";
Python
C++
Exercise 1
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
Programming with C++, Spring 2020, Lecture #22
By Aleksey Gurtovoy
Programming with C++, Spring 2020, Lecture #22
Strict weak ordering, iterators
- 598