Vector Assignment Solution: Implementing Custom Vector Class & Iterators

38 阅读11分钟

Download Link: Vector Assignment Solution: Implementing Custom Vector Class & Iterators

The overall goal of this assignment is to begin programming data structures by implementing your own slimmed-down vector.

Table of Contents

Getting Started

Assignment

Implement Vector

You must implement the following functions for Vector

Implement the Vector’s Iterator

You must implement the following functions for iterator

One Last Function

Further Reading

Run Tests

Turn In

Getting Started

Download this code by running the following command in the directory of your choice:

git clone git@github.com:tamu-edu-students/leyk-csce221-assignment-vector.git

Open the code in your editor of choice. For instance, if you use VS Code:

code .

Note on On OSX you may need to enable the code command in VS Code with Cmd+Shift+P and typing “shell command.” You can select the option to install the command, and then the above command will work.

Assignment

Implement Vector

You are to implement Vector. A Vector is a dynamic array as it is a continuous structure that dynamically updates its capacity as needed. As a result, most operations take constant time to complete. However, the amount of wasted space is often equivalent to the amount used. Therefore, Vector is not a particularly spatially efficient storage structure.

You may have already used std::vector in previous assignments, so your Vector should behave similarly. The big difference is that std::vector decreases its capacity when enough pop_back operations occur, whereas your Vector does not ever need to reduce its capacity.

HINT: Do the following functions first.

Vector()

Vector(size_t count)

~Vector()

size_t size() const noexcept

size_t capacity() const noexcept

T& operator[](size_t pos)

const T& operator[](size_t pos)

– Complete the iterator class

More info about the above functions can be seen below. If you complete the above functions, you should be able to complete any other function and it should pass. The above are the only functions which are “depended on.” Please note that there may be minor exceptions to this rule.

You must implement the following functions for Vector:

—-

“`cpp

// Default Constructor

Vector() noexcept

“`

Description: Create an empty vector.

Parameters: None

Returns: None

Time Complexity: O(1) – Constant Time

Tests: vector_constructor, vector_empty, vector_pop_back, vector_push_back_move, vector_push_back

Link: en.cppreference.com/w/cpp/conta…

—-

“`cpp

// Parameterized Constructor

Vector(size_t count, const T& value)

“`

Description: Constructs the container with count copies of elements with value value.

Parameters:

count The size of the vector to create

value The element to fill the vector with

Returns: None

Time Complexity: O(count)

Tests: vector_erase_multiple, vector_initialization_constructor, vector_iterator_io

Link: en.cppreference.com/w/cpp/conta…

—-

“`cpp

// Parameterized Constructor

explicit Vector(size_t count)

“`

Description: Constructs the container with count default-inserted instances of T. No copies are made.

Parameters:

count The size of the vector to create

Returns: None

Time Complexity: O(count) – Linear Time

Tests: Frequently Tested (vector_default_inserted is dedicated one)

Link: en.cppreference.com/w/cpp/conta…

—-

“`cpp

// Copy Constructor

Vector(const Vector& other)

“`

Description: Constructs the container with the copy of the contents of other.

Parameters:

other The vector to make a copy of. A deep copy should be made.

Returns: None

Time Complexity: O(other.size()) – Linear Time

Tests: vector_copy_constructor

Link: en.cppreference.com/w/cpp/conta…

—-

“`cpp

// Move Constructor

Vector(Vector&& other) noexcept

“`

Description: Constructs the container with the contents of other using move semantics. After the move, other is guaranteed to be empty().

Parameters:

other The vector to move the contents of into a new vector. This should be left empty after this function.

Returns: None

Time Complexity: O(1) – Constant Time

Tests: vector_move_constructor

Link: en.cppreference.com/w/cpp/conta…

—-

“`cpp

// Destructor

~Vector()

“`

Description: Destructs the vector. The destructors of the elements are called, and the used storage is deallocated. Note that if the elements are pointers, the pointed-to objects are not destroyed.

Parameters: None

Returns: None

Time Complexity: O(n)*

Tests: Frequently Tested

Link: en.cppreference.com/w/cpp/conta…

* Depends on the element’s destructor, we are assuming each element’s destructor is O(1)

—-

“`cpp

// Copy Assignment Operator

Vector& operator=(const Vector& other)

“`

Description: Replaces the contents with a copy of the contents of other.

Parameters:

other The vector to make a copy of. The contents of the target vector should be deleted and replaced with a copy of other

Returns: A reference to the target Vector

Time Complexity: O(size() + other.size())

Tests: vector_copy_operator

Link: en.cppreference.com/w/cpp/conta…

—-

“`cpp

// Move Assignment Operator

Vector& operator=(Vector&& other) noexcept

“`

Description: Replaces the contents with those of other using move semantics (i.e. the data in other is moved from other into this container). After the move, other is guaranteed to be empty().

Parameters:

other The vector whose contents should be moved into the target vector. The contents of the target vector should be deleted and replaced with the contents of other, which should be left empty afterwards.

Returns: A reference to the target Vector

Time Complexity: O(size()) – Linear Time

Tests: vector_move_operator

Link: en.cppreference.com/w/cpp/conta…

—-

“`cpp

iterator begin() noexcept

“`

Description: Gets an iterator to the first element in the container. If the container is empty, this should be equivalent to end().

Parameters: None

Returns: An iterator pointing to the first element in the container.

Time Complexity: O(1) – Constant Time

Tests: Frequently Tested (vector_begin is dedicated one)

Link: en.cppreference.com/w/cpp/conta…

—-

“`cpp

iterator end() noexcept

“`

Description: Gets an iterator past the last element in the container. If the container is empty, this should be equivalent to begin().

Parameters: None

Returns: An iterator pointing past the last element in the container.

Time Complexity: O(1) – Constant Time

Tests: vector_end, vector_iterator_arithmetic, vector_iterator_reverse

Link: en.cppreference.com/w/cpp/conta…

—-

“`cpp

[[nodiscard]] bool empty() const noexcept

“`

Description: Checks whether the container is empty.

Parameters: None

Returns: True if the container is empty, false otherwise.

Time Complexity: O(1) – Constant Time

Tests: vector_empty

Link: en.cppreference.com/w/cpp/conta…

—-

“`cpp

size_t size() const noexcept

“`

Description: Returns the number of elements in the vector.

Parameters: None

Returns: The size of the vector.

Time Complexity: O(1) – Constant Time

Tests: Frequently Tested

Link: en.cppreference.com/w/cpp/conta…

—-

“`cpp

size_t capacity() const noexcept

“`

Description: Returns the number of elements that can be held in currently allocated storage.

Parameters: None

Returns: The capacity of the vector (How many elements can fit before needing to resize).

Time Complexity: O(1) – Constant Time

Tests: Frequently Tested

Link: en.cppreference.com/w/cpp/conta…

—-

“`cpp

T& at(size_t pos)

“`

Description: Access element at index pos with bounds checking. Throws std::out_of_range if pos is out of bounds.

Parameters:

pos The index to access.

Returns: A reference to the element at the desired index.

Time Complexity: O(1) – Constant Time

Tests: vector_at

Link: en.cppreference.com/w/cpp/conta…

—-

“`cpp

const T& at(size_t pos) const

“`

Description: Access element at index pos with bounds checking. Throws std::out_of_range if pos is out of bounds.

Parameters:

pos The index to access.

Returns: A const reference to the element at the desired index. The returned element cannot be be used to affect the vector.

Time Complexity: O(1) – Constant Time

Tests: vector_at

Link: en.cppreference.com/w/cpp/conta…

—-

“`cpp

T& operator[](size_t pos)

“`

Description: Access element at index pos without bounds checking.

Parameters:

pos The index to access.

Returns: A reference to the element at the desired index.

Time Complexity: O(1) – Constant Time

Tests: Frequently Tested (vector_access_operator is dedicated one)

Link: en.cppreference.com/w/cpp/conta…

—-

“`cpp

const T& operator[](size_t pos) const

“`

Description: Access element at index pos without bounds checking.

Parameters:

pos The index to access.

Returns: A const reference to the element at the desired index. The returned element cannot be be used to affect the vector.

Time Complexity: O(1) – Constant Time

Tests: Frequently Tested (vector_access_operator is dedicated one)

Link: en.cppreference.com/w/cpp/conta…

—-

“`cpp

T& front()

“`

Description: Access the first element.

Parameters: None

Returns: A reference to the first element in the vector

Time Complexity: O(1) – Constant Time

Tests: vector_front_back

Link: en.cppreference.com/w/cpp/conta…

—-

“`cpp

const T& front() const

“`

Description: Access the first element.

Parameters: None

Returns: A const reference to the first element in the vector

Time Complexity: O(1) – Constant Time

Tests: vector_front_back

Link: en.cppreference.com/w/cpp/conta…

—-

“`cpp

T& back()

“`

Description: Access the last element.

Parameters: None

Returns: A reference to the last element in the vector.

Time Complexity: O(1) – Constant Time

Tests: vector_front_back

Link: en.cppreference.com/w/cpp/conta…

—-

“`cpp

const T& back() const

“`

Description: Access the last element.

Parameters: None

Returns: A const reference to the last element in the vector.

Time Complexity: O(1) – Constant Time

Tests: vector_front_back

Link: en.cppreference.com/w/cpp/conta…

—-

“`cpp

void push_back(const T& value)

“`

Description: Adds value to the end of the vector

Parameters:

value: The value to insert as the new last element using copy semantics.

Returns: None

Time Complexity: O(1) amortized – Constant Time

Tests: vector_move_constructor, vector_pop_back, vector_push_back

Link: en.cppreference.com/w/cpp/conta…

—-

“`cpp

void push_back(T&& value)

“`

Description: Adds value to the end of the vector.

Parameters:

value The value to insert as the new last element using move semantics.

Returns: None

Time Complexity: O(1) amortized – Constant Time

Tests: vector_push_back_move

Link: en.cppreference.com/w/cpp/conta…

—-

“`cpp

void pop_back()

“`

Description: Removes the last element from the vector.

Parameters: None

Returns: None

Time Complexity: O(1) – Constant Time

Tests: vector_pop_back

Link: en.cppreference.com/w/cpp/conta…

—-

“`cpp

iterator insert(iterator pos, const T& value)

“`

Description: Inserts value at position pos.

Parameters:

pos An iterator pointing to the position the element should be inserted. If there is already an element at this position, this element and all following elements should be shifted over.

value The value to insert using copy semantics.

Returns: An iterator pointing to the inserted element.

Time Complexity: O(end() – pos)

Tests: vector_insert

Link: en.cppreference.com/w/cpp/conta…

—-

“`cpp

iterator insert(iterator pos, T&& value)

“`

Description: Inserts value at position pos.

Parameters:

pos An iterator pointing to the position the element should be inserted. If there is already an element at this position, this element and all following elements should be shifted over.

value The value to insert using move semantics.

Returns: An iterator pointing to the inserted element.

Time Complexity: O(end() – pos)

Tests: vector_insert_move

Link: en.cppreference.com/w/cpp/conta…

—-

“`cpp

iterator insert(iterator pos, size_t count, const T& value)

“`

Description: Inserts count copies of value at position pos.

Parameters:

pos The position to start inserting elements at.

count The amount of copies to insert.

value The element to be repeatedly inserted.

Returns: An iterator pointing to the first element inserted.

Time Complexity: O(count + end() – pos)

Tests: vector_insert_multiple

Link: en.cppreference.com/w/cpp/conta…

—-

“`cpp

iterator erase(iterator pos)

“`

Description: Erases element at position pos.

Parameters:

pos An iterator pointing to the element to erase.

Returns: An iterator pointing to the element following the one that was erased. If the last element was erased, should return end().

Time Complexity: O(end() – pos)

Tests: vector_erase

Link: en.cppreference.com/w/cpp/conta…

—-

“`cpp

iterator erase(iterator first, iterator last)

“`

Description: Erases elements in the range [first, last), including first and excluding last.

Parameters:

first An iterator pointing to the first element to erase.

last An iterator pointing to the element ending the range. Elements should be erased up to this point, but not including this element.

Returns: An iterator pointing to the element following the last erased element. If the last element was erased, should return end().

Time Complexity: O(end() – first)

Tests: vector_erase_multiple

Link: en.cppreference.com/w/cpp/conta…

—-

“`cpp

void clear() noexcept

“`

Description: Clears the contents of the vector.

Parameters: None

Returns: None

Time Complexity: O(n) – Linear Time

Tests: vector_clear

Link: en.cppreference.com/w/cpp/conta…

—-

Implement the Vector’s Iterator

You must also implement an inner class iterator in Vector, which can iterate through the elements of the vector forwards and backwards.

You must implement the following functions for iterator:

—-

“`cpp

[[nodiscard]] reference operator*() const noexcept

“`

Description: Accesses the element the iterator point to.

Parameters: None

Returns: A reference to the element the iterator points to.

Time Complexity: O(1) – Constant Time

Tests: vector_begin, vector_end, vector_iterator_arithmetic, vector_iterator_forward, vector_iterator_io, vector_iterator_reverse

—-

“`cpp

[[nodiscard]] pointer operator->() const noexcept

“`

Description: Accesses a member or method of the element the iterator points to.

Parameters: None

Returns: A pointer to the element the iterator points to.

Time Complexity: O(1) – Constant Time

Tests: vector_iterator_io

—-

“`cpp

iterator& operator++() noexcept

“`

Description: Prefix increment (++i). The iterator should be advanced forward by one element and returned.

Parameters: None

Returns: A reference to the advanced iterator.

Time Complexity: O(1) – Constant Time

Tests: vector_iterator_forward

—-

“`cpp

iterator operator++(int) noexcept

“`

Description: Postfix increment (i++). The iterator should be advanced forward by one element, but a copy of before it was advanced should be returned.

Parameters: None

Returns: A copy of the iterator before it was advanced.

Time Complexity: O(1) – Constant Time

Tests: vector_iterator_arithmetic, vector_iterator_comparison, vector_iterator_forward

—-

“`cpp

iterator& operator–() noexcept

“`

Description: Prefix decrement (–i). The iterator should be retreated backward by one element and returned.

Parameters: None

Returns: A reference to the retreated iterator.

Time Complexity: O(1) – Constant Time

Tests: vector_iterator_reverse

—-

“`cpp

iterator operator–(int) noexcept

“`

Description: Postfix decrement (i–). The iterator should be retreated backward by one element, but a copy of before it was retreated should be returned.

Parameters: None

Returns: A copy of the iterator before it was retreated.

Time Complexity: O(1) – Constant Time

Tests: vector_iterator_reverse

—-

“`cpp

iterator& operator+=(difference_type offset) noexcept

“`

Description: Advances the iterator forward by an offset.

Parameters:

offset How far to advance the iterator.

Returns: A reference to the iterator after it was advanced offset forward.

Time Complexity: O(1) – Constant Time

Tests: vector_iterator_arithmetic

—-

“`cpp

[[nodiscard]] iterator operator+(difference_type offset) const noexcept

“`

Description: Returns a copy of the iterator advanced forward by an offset.

Parameters:

offset How far the copy should be ahead of the iterator.

Returns: An iterator offset ahead of the current iterator.

Time Complexity: O(1) – Constant Time

Tests: vector_erase_multiple, vector_erase, vector_insert_move, vector_insert_multiple, vector_insert, vector_iterator_arithmetic

—-

“`cpp

iterator& operator-=(difference_type offset) noexcept

“`

Description: Retreats the iterator backwards by an offset.

Parameters:

offset How far to retreat the iterator.

Returns: A reference to the iterator after it was retreated offset backwards.

Time Complexity: O(1) – Constant Time

Tests: vector_iterator_arithmetic

—-

“`cpp

[[nodiscard]] iterator operator-(difference_type offset) const noexcept

“`

Description: Returns a copy of the iterator retreated backwards by an offset.

Parameters:

offset How far the copy should be behind the iterator.

Returns: An iterator offset behind the current iterator.

Time Complexity: O(1) – Constant Time

Tests: vector_end, vector_iterator_arithmetic

—-

“`cpp

[[nodiscard]] difference_type operator-(const iterator& rhs) const noexcept

“`

Description: Finds how far apart two iterators are. Used as iter1 – iter2.

Parameters:

rhs The iterator to compare with the current iterator

Returns: The distance between the the current iterator and rhs.

Time Complexity: O(1) – Constant Time

Tests: vector_erase_multiple, vector_erase, vector_insert_move, vector_insert_multiple, vector_insert, vector_iterator_arithmetic

—-

“`cpp

[[nodiscard]] reference operator[](difference_type offset) const noexcept

“`

Description: Gets a reference an element offset from the iterator.

Parameters:

offset How far from the iterator the desired element is.

Returns: The element offset ahead of the iterator.

Time Complexity: O(1) – Constant Time

Tests: vector_iterator_arithmetic

—-

“`cpp

[[nodiscard]] bool operator==(const iterator& rhs) const noexcept

“`

Description: Checks if two iterators are equal.

Parameters:

rhs The iterator to compare the current iterator to.

Returns:

true If the two iterators are equal

false If they are not

Time Complexity: O(1) – Constant Time

Tests: vector_iterator_comparison

—-

“`cpp

[[nodiscard]] bool operator!=(const iterator& rhs) const noexcept

“`

Description: Checks if two iterators are not equal.

Parameters:

rhs The iterator to compare to.

Returns:

true If the two iterators are not equal

false If they are equal

Time Complexity: O(1) – Constant Time

Tests: vector_iterator_comparison

—-

“`cpp

[[nodiscard]] bool operator<(const iterator& rhs) const noexcept

“`

Description: Checks if an iterator comes before another.

Parameters:

rhs The iterator to compare to.

Returns:

true If the current iterator comes before rhs

false If it does not

Time Complexity: O(1) – Constant Time

Tests: vector_iterator_comparison

—-

“`cpp

[[nodiscard]] bool operator>(const iterator& rhs) const noexcept

“`

Description: Checks if an iterator comes after another.

Parameters:

rhs The iterator to compare to.

Returns:

true If the current iterator comes after rhs

false If it does not

Time Complexity: O(1) – Constant Time

Tests: vector_iterator_comparison

—-

“`cpp

[[nodiscard]] bool operator<=(const iterator& rhs) const noexcept

“`

Description: Checks if an iterator comes before or is equal to another.

Parameters:

rhs The iterator to compare to.

Returns:

true If the current iterator comes before or is equal to rhs

false If it is not

Time Complexity: O(1) – Constant Time

Tests: vector_iterator_comparison

—-

“`cpp

[[nodiscard]] bool operator>=(const iterator& rhs) const noexcept

“`

Description: Checks if an iterator comes after or is equal to another.

Parameters:

rhs The iterator to compare to.

Returns:

true If the current iterator comes after or is equal to rhs

false If it is not

Time Complexity: O(1) – Constant Time

Tests: vector_iterator_comparison

—-

One Last Function

There is a small function not a part of the Vector class at the bottom of Vector.h, which overloads adding an iterator to an offset. This allows for the addition between an iterator and an offset to be commutative

—-

“`cpp

[[nodiscard]] _Iterator operator+(typename _Iterator::difference_type offset, _Iterator const& iterator) noexcept

“`

Description: Returns a copy of an iterator advanced forward by an offset.

Parameters:

offset How far the copy should be ahead of the iterator.

iterator The iterator to compare to move forward from.

Returns: An iterator offset ahead of iterator.

Time Complexity: O(1) – Constant Time

Tests: vector_iterator_arithmetic

—-

Further Reading

Feel free to read about const_iterator and reverse_iterator in C++. However, you need only implement iterator for this assignment.

It may be helpful for you to consult:

– Reference for Iterators: en.cppreference.com/w/cpp/itera…

– Reference for Vector Begin: en.cppreference.com/w/cpp/conta…

– Reference for Vector End: en.cppreference.com/w/cpp/conta…

– Reference for List Begin: en.cppreference.com/w/cpp/conta…

– Reference for List End: en.cppreference.com/w/cpp/conta…

—-

Run Tests

Execute the following commands from the leyk-csce221-assignment-vector folder to accomplish what you need:

Build all of the tests

“`sh

make -C tests -j12 build-all

“`

Run the test called <test-name>. Replace <test-name> with the name of any .cpp file in the ./tests/tests folder.

“`sh

make -C tests -j12 run/

“`

Run every test in the ./tests/tests folder.

“`sh

make -C tests -j12 run-all -k

“`

Debugging tests

“`sh

make -C tests -j12 build-all -k

cd tests/build

gdb

cd ../..

“`

Alex recommends you use cgdb which has the same commands as gdb but a better user interface. You can install it with sudo apt install cgdb on WSL or brew install cgdb on MacOS (provided you have brew)

The first command builds the tests, the next enters the folder where the tests were build. The third invokes gdb (use lldb if on Mac OSX) which is used to debug the program by examining Segmentation Faults and running code line-by-line. Finally, the last command takes you back to the top-level directory.

Turn In

Submit the modified Vector.h to Gradescope. In general, submit everything except main.cpp.