CS 70

Implementing IntList, Phase 4: The Finishing

In this part, we'll add the finishing touches to the IntList class.

The Interface

The functions we need to implement are:

(copy constructor)
Makes a duplicate copy of another IntList.
(assignment operator)
Replaces the contents of this list with a duplicate copy of another IntList.
(equality operator)
Checks if two IntList objects are equal.
(inequality operator)
Checks if two IntList objects are not equal.

All these functions are \( \mathrm{O}(n) \), where \( n \) is the number of elements in the list. Copying and assignment are \( \Theta(n) \), because we have to copy each element. Equality and inequality are \( \Theta(n) \) in the worst case because we may have to compare each element, but they are \( O(1) \) in the best case because we may be able to determine that the lists are unequal by just looking at their sizes or by finding a mismatch on the first element.

Your Task, Part 1: Planning the Implementation

Although you should plan out these functions for yourselves, we'll give some strong hints about how to implement them.

  • LHS Cow speaking

    You may also want revisit this lesson to remind yourselves about implementing copy constructors and assignment operators for classes that manage their own dynamic memory.

Copy Constructor

Use a loop to iterate through the other list, using push_back to add each element to the new list.

Assignment Operator

Use the copy-and-swap idiom. Make a copy of the other list in a temporary variable, then swap it with the current list. The temporary variable will then go out of scope and its destructor will clean up the old contents of the current list.

Equality Operator

First, check to see if the sizes are different. If they are, the lists are not equal and you're done. If the sizes aren't different, use a loop to compare each element.

Inequality Operator

This operator can be implemented in terms of the equality operator. If the equality operator returns false, then the lists are not equal.

Planning Evidence

Although you're welcome to plan things out on paper, you don't need to submit any planning evidence for this part of the assignment.

  • Goat speaking

    Meh. I'll skip the planning.

  • LHS Cow speaking

    Just because we say you don't need to submit planning evidence doesn't mean you don't have to think about how you're going to implement these functions. If the descriptions above seem completely clear to you, then that's fine, but if anything seem unclear, you should definitely take some time to think about it before you start coding.

Your Task, Part 2: Adding the Declarations

First, remove the = delete lines in intlist.hpp that disable copying and assignment. Then, add the following declarations, but include docstring comments describing what each function does, its parameters, return value, rules for usage, and complexity.

IntList(const IntList& other);
IntList& operator=(const IntList& other);
bool operator==(const IntList& other) const;
bool operator!=(const IntList& other) const;

You can check to be sure that you haven't introduced any syntax errors in the header by running make intlist.o.

Your Task, Part 3: Writing Test Cases for the New Functions

In intlist-test.cpp, extend your test cases to test the new functions. Think about the edge cases you need to test, especially when the list has only one element or none.

You can check your code for syntax errors by running make intlist-test.o. Obviously, you can't test against IntList yet, since you haven't implemented these functions, but at least you can check for serious issues with the tests. (If you disable your tests for insert_after, you could check your tests against IntVector, but that's not required and probably not a good use of your time.)

Your Task, Part 4: Implementing and Testing the New Functions

Now that you have a plan and test cases, it's time to implement the new functions in intlist.cpp. If your new functions only call preexisting functions, you don't need to add a call to check_invariants() (because they already call it), but if you write any new code that modifies the list's data members directly (why?), make sure you add a call to check_invariants() at the end of the function, to catch any accidental violations of invariants.

Once they're written, run your test cases to check that they work correctly.

cs70-make -H intlist-test
./intlist-test

As usual, if things fail, you can use valgrind to help you find the problem and all the usual debugging advice applies.

  • Cat speaking

    Okay, we've built a pretty general singly linked list class. We can use it like a stack or a queue, iterate through it, insert elements in the middle, copy it, assign it, compare it… Nice.

  • Dog speaking

    I'm happy!

  • Horse speaking

    I'm not seeing anything missing.

  • Goat speaking

    Meh. I think it was all pointless. C++ already has std::list which does all this and more.

  • LHS Cow speaking

    Well, yes, but std::list is a doubly linked list, which is more complicated than what we need for the Snake game.

  • Goat speaking

    Meh. There's not going to be a performance difference. It's all just constant-time operations. So they'll be the same, right?

  • LHS Cow speaking

    Not quite. An asymptotic perspective ignores constant factors that matter in real code. A doubly linked list uses more memory per node and has more complex code, both of which might lower performance. The only to answer your question, Goat, is for us to conduct some experiments.

  • Goat speaking

    Bah! I wasn't asking for more work!!!

  • Pig speaking

    MORE to learn about! Oh YEAH!!!

  • Dog speaking

    Doing some actual science in computer science! Woo-hoo! I'll fetch my labrador coat!

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.)