Answered step by step
Verified Expert Solution
Link Copied!

Question

1 Approved Answer

11.14 Programming Project #6: Dynamic Arrays Background Earlier in the semester, you studied the concept of a vector. As you recall, a vector acts very

11.14 Programming Project #6: Dynamic Arrays Background Earlier in the semester, you studied the concept of a vector. As you recall, a vector acts very much like an array, except that a vector automatically grows to hold more data as needed. In this project, you will create a class that works like a vector of integers. An important element in the design of a vector is the use of a private, dynamically allocated array, via a pointer that keeps track of where the array is in memory. As you continue your training as a programmer, you will need to master the use of dynamically allocated storage and pointers. Important note: Just to be clear, you may not use std::vector to do any of this you are creating your own vector class! You will write code that constitutes the beginning of the real vector class in the C++ library (except that DynArray will not be genericit will only hold integers). We will use the original name used by the C++ Standards Committee before they changed it to vector: DynArray (for "dynamic array", pronounced DINE-array). Objective To gain confidence in the use of pointers and dynamically allocated storage. The DynArray Class For efficiency of operation, DynArray has two notions of size: the current capacity, which is the size of the allocated array in the heap the actual size, which is the number of elements in use If these values are the same, then the array is full and needs to be made larger before it can add more items. This is done by: allocating a new, larger array (typically 1.5-to-2 times the current capacity) copying the currently used data to the first "size" locations of the new array deleting the old array, thus returning its memory to the heap having your internal pointer point to the new heap array In order to operate like a true vector, your class must contain at least the following functions: A default constructor that creates a DynArray with a default capacity of 2. Its size will initially be zero. Remember that size refers to the number of elements currently stored by the user in the DynArray. A parameterized constructor receiving an integer, n, that creates a DynArray of capacity n. Its size will initially be zero. A destructor that deletes any dynamically allocated storage. This prevents a memory leak. A function size() that returns the current size of your DynArray instance. The size will change as integer values are added or removed. A function capacity() that returns the current allocated capacity of the DynArray. The capacity is defined as the number of integer values that can be stored in the DynArray instance. The capacity changes when the underlying array grows. A function clear() that returns the dynamic memory to the heap, and resets its size to zero and capacity to the default of two, allocating fresh heap memory. A function push_back(int n) that adds the integer value n to the end of the DynArray. If it is not large enough to hold this additional value, you must increase the size of the backing array, as explained above. A function pop_back(), that decrements the size of the DynArray by 1. No change is made to the allocation. A function at(int n) that returns the value of the integer stored at index n of the DynArray. If the index is outside the range of the vector (no element at that index), this function should throw a std::runtime_error with an appropriate message. Vector Internals In order to make a DynArray instance grow, you will need to use dynamically allocated storage. Vectors actually store their data in a array allocated on the heap. You will store a pointer to this array in am instance of the DynArray class. You will also need to track the size of the allocated array (its capacity, which is the number of ints it can hold altogether), and the size, which is the number of elements in use by the user of the DynArray object (element in positions 0 through size - 1). Each time that you add a new element to the vector, its size increases by one. The figure below shows a DynArray object and its associated dynamically allocated array of integers. vector internals Values are inserted into the vector using the push_back function. Since we always know the size of a vector, it is easy to calculate where in the array we store the value that is being pushed-back (it will be in position size). Consider, for example, a vector whose capacity is currently 5, and whose size is 3. This means that we have an array that can hold 5 integer values, but we have only stored 3 values in the array so far. These values are stored in the array at index 0, index 1, and index 2. There are actually values stored at the other indices of the array, but this is garbage. We show this with a dash. This is illustrated in the figure below. push back If we now do a push_back(91), we just store the value 91 in the next available slot in the array, which is at index 3. Now we increment the index. The capacity does not change. Growing the Vector takes more work. What do we do when the vector is full? Here is the process: Dynamically allocate a new array of integers that is somewhat larger than the existing array. An algorithm that is often used is to double the size of the array. Copy all of the numbers from the first array into the second, in sequence. Add the new value at the next open slot in the new array (size). Change capacity to be the capacity of the new array. Increment size Delete the original array. Change the data pointer to now point to the new array. This is illustrated in the following figure: grow Destructors Destructors are use to gracefully destroy class instances. If a class instance has a pointer that refers to heap memory, then the dsestructor should return that memory to the heap by calling delete on the pointer. Destructors are called automatically when an object goes out of scope (like when execution exits a {}-block or returns from a function). Failing to do this makes the memory unavailable and is called a memory leak. It is good practice to design classes to be self-managing: constructors place new objects in a valid state, and destructors free any dynamic resources. If a class uses no dynamic resources (such as memory, network connections, etc.), then a destructor probably isn't needed. The driver for this project is provided for you and does the following: Create an empty vector Add three values to the vector in this order: 21,32,41 using push_back Test at() to verify that it catches an attempt to access a position out of bounds Clear the vector Add 12 values to the vector from 0 to 11 using push_back Output the size of the vector Output the capacity of the vector Display the values in the vector Here is the expected output using the main.cpp provided for you:

//given main

#include

#include "dynarray.h"

using namespace std;

int main()

{

// Create a default vector (cap = 2)

DynArray sam;

cout << "capacity = " << sam.capacity() << endl;

// push some data into sam

cout << " Pushing three values into sam";

sam.push_back(21);

sam.push_back(31);

sam.push_back(41);

cout << " The values in sam are: ";

// test for out of bounds condition here

for (int i = 0; i < sam.size() + 1; i++)

{

try

{

cout << sam.at(i) << " ";

}

catch(runtime_error& x)

{

cout << x.what() << endl;

}

}

cout << " -------------- ";

// clear sam and display its size and capacity

sam.clear();

cout << " sam has been cleared.";

cout << " Sam's size is now " << sam.size();

cout << " Sam's capacity is now " << sam.capacity() << endl;

cout << "--------------- ";

// Push 12 values into the vector - it should grow

cout << " Push 12 values into sam.";

for (int i = 0; i < 12; i++)

sam.push_back(i);

cout << " Sam's size is now " << sam.size();

cout << " Sam's capacity is now " << sam.capacity() << endl;

cout << "--------------- ";

cout << " Test to see if contents are correct...";

// display the values in the vector

for (int i = 0; i < sam.size( ); i++)

{

cout << sam.at(i) << " ";

}

cout << " -------------- ";

cout << " Test pop_back...";

// display the values in the vector

sam.pop_back();

for (int i = 0; i < sam.size( ); i++)

{

cout << sam.at(i) << " ";

}

cout << endl;

}

Step by Step Solution

There are 3 Steps involved in it

Step: 1

blur-text-image

Get Instant Access to Expert-Tailored Solutions

See step-by-step solutions with expert insights and AI powered tools for academic success

Step: 2

blur-text-image

Step: 3

blur-text-image

Ace Your Homework with AI

Get the answers you need in no time with our AI-driven, step-by-step assistance

Get Started

Recommended Textbook for

The Structure Of The Relational Database Model

Authors: Jan Paredaens ,Paul De Bra ,Marc Gyssens ,Dirk Van Gucht

1st Edition

3642699588, 978-3642699580

More Books

Students also viewed these Databases questions

Question

A Turing machine can accept any regular language. True False

Answered: 1 week ago

Question

to encourage a drive for change by developing new ideas;

Answered: 1 week ago

Question

4 What are the alternatives to the competences approach?

Answered: 1 week ago