CS 70

Phase 3

In this step, you will provide iteration for IntList objects by implementing the following member function(s) of the IntList class,

  • begin()
  • end()

and implement the following member function(s) of the IntList::Iter class,

  • operator*() (the indirection operator)
  • operator++() (the increment operator)
  • operator==(…) (the equal-to operator)

These operations are described in the

which also describes the encoding for iterators with a useful diagram. You should have the spec open in another window or tab so you can easily consult it as you work, but for your convenience, the diagram is also reproduced here:

Steps

  • LHS Cow speaking

    As you did with the last phase, work through the four steps in order as shown.

  • RHS Cow speaking

    And, as always, remember to check out the Helpful Hints!

1. Plan

The encoding for IntList::Iter is already determined; it is a class that stores a pointer to a Node (in current_). What remains is for you to figure out

  1. What *iter does to return the integer stored inside the node.
  2. In the diagram above, the iterator is set to the second node in the list. How can we get to the integer 24 that it contains?
  3. What ++iter will do to move on to the next node.
  4. In the diagram above, would need update current_ from its present value, h78, now point to the next node in list, which is h56. How do we get that value?
  5. How iter1 == iter2 will determine whether the two iterators are set to the exact same list node.

Also, in the IntList class, the begin() and end() member functions need to make Iter objects and return them. You'll need to figure out

  1. What myList.begin() should return.
  2. In the diagram above, it returns an Iter with current_ set to h42. How would we do that?
  3. What myList.end() should return.
  4. Note that if you've correctly figured out ++, you just need to think about what will actually happen if you have an iterator set to the last node in the list (h56 in our diagram) and then call ++ on that iterator. Whatever value the iterator is then set to is the past-the-end value.

Note that the Iter class has two constructors, both of which have been provided. They are

  • A public default constructor to create an iterator that isn't set at any node in any list.
    • Any external code can create a default-constructed iterator but they shouldn't use it for anything!
  • A private (explicit) parameterized constructor that takes a Node* and constructs an iterator object, initializing current_ to be the provided Node* parameter.
    • We would use this constructor in begin() and end() to make iterators that are set at particular nodes.
  • Horse speaking

    Hay, if the parameterized constructor is private, how can we call it from begin()? That's in IntList, not in IntList::Iter.

  • LHS Cow speaking

    Good question!

We want the parameterized constructor to be private because we don't want just anyone to be able to make an Iter out of a pointer they happen to have. The problem is that we really need code in IntList to be able to construct Iter objects using this constructor.

Friendship

  • Dog speaking

    Now this is a topic I know a lot about! Let's be friends!!!

  • LHS Cow speaking

    Yes, let's! But that's not really what this is about. We have a problem to solve.

  • Dog speaking

    A problem that we will solve with... THE POWER OF FRIENDSHIP!!

  • LHS Cow speaking

    Sort of...?

In intlist.hpp, note the line that says

friend class IntList;

This line declares the class IntList as a friend to IntList::Iter. A friend of IntList::Iter can access members marked private in IntList::Iter. So code within IntList (e.g. begin() and end()) can call the private constructor and even directly access current_.

  • Duck speaking

    Doesn't friend-ship ruin the whole "keep the encoding private" thing?

  • LHS Cow speaking

    It definitely can! You should use this tool with caution.

  • RHS Cow speaking

    But remember that you can only declare a class as a friend if you know about it!

  • LHS Cow speaking

    That does prevent you from accidentally exposing the encoding to arbitrary code.

  • RHS Cow speaking

    The most important use is for classes that are designed to work very closely together (a list and its nodes, a collection and its iterator, etc.).

  • LHS Cow speaking

    Ideally, as a collective, they will still hide away the implementation details.

Don't Overcomplicate Things!

Although you might have to think and look at the diagram above to figure out what needs to be done, once you've figured it out, it should be very straightforward. If you've done things correctly, there should be no need for loops, or even conditional code. Oftentimes, students wonder “Is this it?? That's all?”

  • Alien speaking

    Many of my people wonder the same thing.

Also note that when there is no difference at all in implementation between the const and non-const versions of begin() and end(). You'll write the code for the non-const version, and then just paste the exact same code into the const version and it'll work.

  • Cat speaking

    Isn't it bad to copy and paste code?

  • LHS Cow speaking

    Given how simple these functions should be, it's fine.

Add and Upload Your Image File

For this phase, add your plan as Phase_3.jpg to the intlist/Planning folder in your assignment repository (git add; git commit; git push). Make sure the file was added successfully by viewing it on the GitHub website.

2. Write Tests

Next, you need to write some tests.

The user-visible functionality of a list iterator is independent of the specific encoding and implementation choices we've made for our IntList::Iter class. So in some sense, none of the planning you've done above directly factors into testing, as the only question is “does it work properly as an iterator”.

So, here are some things that should be true of any iterator on any kind of container:

  • begin() is equal to end() if and only if the container is empty.
  • If you insert some numbers into the container, you should be able to iterate over the container and read back those same numbers.

Maybe you can come up with another couple of ideas.

But you can also think about how someone else might have misunderstood or overcomplicated things when doing the planning stage, and how that issue might show up in an incorrect implementation.

  • RHS Cow speaking

    Also, don't forget to add your test functions to main so they actually get called!

3. Implement

Use your plan to write the iterator. If your plan is correct, it isn't much code to write.

4. Test & Debug

Test your iterator and debug as needed.

Helpful Hints

Return value of operator++()

In C++, it is legal to run ++(++iter) to advance an iterator twice. So saying ++iter doesn't just update iter to advance it, it also returns a reference to iter so that more further operations can be performed. In other words, you need to end with

return *this;

so that the member function returns the object it was called on.

Checking for Misuse

  • Sheep speaking

    Should I check for misuse?

  • Goat speaking

    You don't have to. I'm not bothering.

  • LHS Cow speaking

    But there are some very simple checks you can add to code that'll catch some kinds of misuse.

  • RHS Cow speaking

    But some other kinds of misuse would be very hard to detect.

For example, you probably can catch * or ++ on end() or a default constructed iterator.

The explicit Keyword

  • Horse speaking

    Hay! Why is the deal with the explicit keyword in the single-parameter constructor for IntList::Iter?

  • Rabbit speaking

    Without it, C++ would be happy to automatically convert Node* values into IntList::Iter values.

  • LHS Cow speaking

    Basically, we're turning off some peculiar automatic behavior that you wouldn't have ever expected, doesn't help, and we don't want.

Whenever you write a single-parameter constructor in C++, it is almost always best to declare it explicit.

To Complete This Part of the Assignment…

You'll know you're done with this part of the assignment when you've done all of the following:

(When logged in, completion status appears here.)