Iterator Lab
In this lab, we will look at iterating over a non-container.
We could have just as well called this the “Virtual Container Lab”,
but the multiple meanings of virtual
would confuse things.
                
The files for this lab are in ~cs253/Lab/Iterator.
Copy them to a temporary directory.
                
A Non-Container
If someone asked you to name the continents, you might say:
- Africa
- Asia
- North America
- South America
- Australia
- Antarctica
(Then, an enjoyable argument about Europe would break out.)
                
Did you actually have that list of continents written down, and
you iterated over them? Probably not. Instead, you generated
that list, as needed. Similarly, in C++, we sometimes want to
iterate over “containers” that don’t really hold anything, but instead
have dynamically-generated contents.
Like we did for regular expressions with sregex_iterator
.
                
Directory Iteration with Linux System Calls
Consider this program, dir-simple.cc:
                
#include <iostream> // for cout
#include <string> // for "…"s
#include <dirent.h> // for opendir, readdir, closedir
using namespace std;
int main() {
DIR *dp = opendir(".");
while (dirent *d = readdir(dp))
if (d->d_name != "."s && d->d_name != ".."s)
cout << "Filename: " << d->d_name << '\n';
closedir(dp);
return 0;
}
Note that d->d_name
is a C string, but "
…"s
is a C++ string,
so !=
comparison works.
                
It displays all the files in the current directory (“.”) except for
the current directory itself (“.”) and the parent directory (“..”).
It does so with the opendir
/ readdir
/ closedir
functions.
                
Every time readdir
is called, it reads another directory entry
from the disk, in a system-dependent manner. It returns a pointer
to a struct
that contains the d_name
field, a C-style string.
If readdir
runs out of names in the directory, it returns
a null pointer.
                
This program is certainly not in our usual C++ style, but it works.
                
Directory Iteration in the C++ Manner
dir-object.cc is more in C++ style:
                
#include <iostream>
#include "Directory.h"
using std::cout;
int main() {
Directory dir(".");
for (auto name : dir)
cout << "Filename: " << name << '\n';
}
We have a “container”, of type Directory
, initialized with “.”, the
current directory. We then iterate over that container using a typical
for-each loop.
                
Of course, there’s complexity hidden in Directory.h
and Directory.cc. Unsurprisingly, they use the
opendir
/ readdir
/ closedir
functions.
                
Understanding the code
As a group, discuss and understand Directory.h and
Directory.cc.
                
Points to consider:
- Why doesn't the
Directory
ctor just read everything into a vector
?
- What about iterator post-increment?
- What about iterator
==
?
Exercises
- What happens when the
Directory
ctor is given a non-existant
directory name? Try it. Fix it.
- It’s cumbersome for the
.
and ..
filtering code to be in
operator++
. Make it a separate, private
method called
.wanted()
.
- Add a second, optional, argument to the
Directory
ctor
that specifies a regular expression
of filenames to match. For example, Dir foo(".", "a.*b")
would yield rabbit
and catbird
, but not zulu
.
Do the pattern-matching in your new .wanted()
method.
- Show your work to the TA.