I am currently working on a Vector class. I am required to use certain concepts such as templates, etc. For the most part I have completed the entire project, except there is a memory leak in which I'm unable to locate.
I'm using macOS Catalina and I've tried to install Valgrind however I cannot seem to get it to work. That is another issue in and of itself. Where is the memory leak located? And what is an easy way to detect where memory leaks are for macOS Catalina users?
I'm also using VS Code.
HEADER FILE
Note: ContainerIfc is an abstract class, all methods are implemented below that are needed to understand.
#ifndef PROJ7_MYVECTOR
#define PROJ7_MYVECTOR
#include "proj7-ContainerIfc.h"
template <class T>
class MyVector : public ContainerIfc<T>
{
public:
/**
* MyVector
*
* This is the default constructor that sets size equal
* to 0 and capacity to 10.
*
* Parameters: none
*
* Output:
* return: none
* reference parameters: none
* stream: none
*/
MyVector();
/**
* ~MyVector
*
* This is the destructor that deletes memory
*
* Parameters: none
*
* Output:
* return: none
* reference parameters: none
* stream: none
*/
~MyVector();
/**
* MyVector
*
* This is the copy constructor
*
* Parameters:
* v: the object that you want to copy over
*
* Output:
* return: none
* reference parameters: none
* stream: none
*/
MyVector(const MyVector &);
/**
* = operator
*
* This is the overloaded assignment operator
*
* Parameters:
* v: the object that you want to copy over
*
* Output:
* return: none
* reference parameters: none
* stream: none
*/
MyVector<T> &operator=(const MyVector &);
/**
* pushFront
*
* Prepends a value to the array
*
* Parameters:
* e: The value that you want to prepend
*
* Output:
* return: none
* reference parameters: none
* stream: none
*/
MyVector<T> &pushFront(T);
/**
* pushBack
*
* Appends a vlue to the array
*
* Parameters:
* e: The value that you want to append
*
* Output:
* return: none
* reference parameters: none
* stream: none
*/
MyVector<T> &pushBack(T);
/**
* popFront
*
* Removes the first index of the array and shifts all elements leftward
*
* Parameters:
* e: The value that was removed
*
* Output:
* return: none
* reference parameters: e
* stream: none
*/
MyVector<T> &popFront(T &);
/**
* popBack
*
* Removes the last index of the array
*
* Parameters:
* e: The value that was removed
*
* Output:
* return: none
* reference parameters: none
* stream: none
*/
MyVector<T> &popBack(T &);
/**
* front
*
* Returns the first element of the array
*
* Parameters: none
*
* Output:
* return: Copy of the first data item in the MyVector
* reference parameters: none
* stream: none
*/
T front();
/**
* back
*
* Returns the last element of the array
*
* Parameters: none
*
* Output:
* return: Returns a copy of the last data item in MyVector
* reference parameters: none
* stream: none
*/
T back();
/**
* [] operator
*
* Returns a reference to data element n in MyVector
*
* Parameters:
* n: index of item to return
*
* Output:
* return: Returns a reference to data element n in MyVector
* reference parameters: none
* stream: none
*/
T &operator[](int);
/**
* getSize
*
* Returns size of MyVector array
*
* Parameters: none
*
* Output:
* return: an integer value representing the number of elements in the list
* reference parameters: none
* stream: none
*/
int getSize();
/**
* isEmpty
*
* Returns state information about the list
*
* Parameters: none
*
* Output:
* return: Returns state information about the list
* reference parameters: none
* stream: none
*/
bool isEmpty();
/**
* erase
*
* Erases a vector
*
* Parameters: none
*
* Output:
* return: none
* reference parameters: none
* stream: none
*/
void erase();
private:
T *data;
int size;
int capacity;
/**
* grow
*
* Increases the capacity of data by doubling the previous value and allocating
* the appropriate memory for data
*
* Parameters: none
*
* Output:
* return: none
* reference parameters: none
* stream: none
*/
void grow();
/**
* shiftRight
*
* Shifts all values in the array one space to the right
*
* Parameters: none
*
* Output:
* return: none
* reference parameters: none
* stream: none
*/
void shiftRight();
/**
* shiftLeft
*
* Shifts all values in the array one space to the left
*
* Parameters: none
*
* Output:
* return: none
* reference parameters: none
* stream: none
*/
void shiftLeft();
};
template <class T>
MyVector<T>::MyVector()
{
this->size = 0;
this->capacity = 10;
this->data = new T[this->capacity];
}
template <class T>
MyVector<T>::~MyVector()
{
delete[] this->data;
}
template <class T>
MyVector<T>::MyVector(const MyVector &v)
{
this->size = v.size;
this->capacity = v.capacity;
this->data = new T[this->capacity];
// Copy each array item over
for (int i = 0; i < this->size; i++)
{
this->data[i] = v.data[i];
}
}
template <class T>
MyVector<T> &MyVector<T>::operator=(const MyVector &v)
{
this->size = v.size;
this->capacity = v.capacity;
this->data = new T[this->capacity];
// Copy each array item over
for (int i = 0; i < this->size; i++)
{
this->data[i] = v.data[i];
}
return *this;
}
template <class T>
MyVector<T> &MyVector<T>::pushFront(T e)
{
// Resize if necessary
if (this->size == this->capacity)
{
this->grow();
}
// Shift elements to the right
this->shiftRight();
// Add new value to first index of array
this->data[0] = e;
// Increment size
this->size++;
return *this;
}
template <class T>
MyVector<T> &MyVector<T>::pushBack(T e)
{
// Resize if necessary
if (this->size == this->capacity)
{
this->grow();
}
// Add value to array
this->data[this->size] = e;
// Increment size
this->size++;
return *this;
}
template <class T>
MyVector<T> &MyVector<T>::popFront(T &e)
{
// Throw BADINDEX if empty
if (this->size <= 0)
{
throw BADINDEX();
}
// Set e equal to the first value
e = this->front();
// Shift elements to the left removing the first index
this->shiftLeft();
// Decrement size
this->size--;
return *this;
}
template <class T>
MyVector<T> &MyVector<T>::popBack(T &e)
{
// Throw BADINDEX if empty
if (this->size <= 0)
{
throw BADINDEX();
}
// Set e equal to the last value
e = this->back();
// Remove last element by creating new array and copying values
T *temp = new T[this->capacity];
// Ignore last element and copy all values
for (int i = 0; i < this->size - 1; i++)
{
temp[i] = this->data[i];
}
// Deallocate current array
delete[] this->data;
// Allocate new temp array
this->data = temp;
// Decrement size
this->size--;
return *this;
}
template <class T>
T MyVector<T>::front()
{
// Throw BADINDEX if empty
if (this->size <= 0)
{
throw BADINDEX();
}
return this->data[0];
}
template <class T>
T MyVector<T>::back()
{
// Throw BADINDEX if empty
if (this->size <= 0)
{
throw BADINDEX();
}
return this->data[this->size - 1];
}
template <class T>
T &MyVector<T>::operator[](int n)
{
// Throw BADINDEX if n doesn't exist
if (n > this->size - 1)
{
throw BADINDEX();
}
return this->data[n];
}
template <class T>
int MyVector<T>::getSize()
{
return this->size;
}
template <class T>
bool MyVector<T>::isEmpty()
{
bool isEmpty = true;
// Check if size is greater than 0
if (this->size > 0)
{
isEmpty = true;
}
return isEmpty;
}
template <class T>
void MyVector<T>::erase()
{
// Erase vector by deallocating and allocating a new one
// Reset size & capacity
this->size = 0;
this->capacity = 10;
// Create new empty array
T *temp = new T[this->capacity];
// Delete old array
delete[] this->data;
// Set current array to new array
this->data = temp;
}
template <class T>
void MyVector<T>::grow()
{
// Double capacity as instructions say
this->capacity *= 2;
T *temp = new T[this->capacity];
// Copy each array item over
for (int i = 0; i < this->size; i++)
{
temp[i] = this->data[i];
}
// Deallocate current array
delete[] this->data;
// Allocate new temp array
this->data = temp;
}
template <class T>
void MyVector<T>::shiftRight()
{
// Create a new array
T *temp = new T[this->capacity];
// Copy values over shifting one to the right
for (int i = 1; i < this->size + 1; i++)
{
temp[i] = this->data[i - 1];
}
// Deallocate current array
delete[] this->data;
// Allocate new temp array
this->data = temp;
}
template <class T>
void MyVector<T>::shiftLeft()
{
// Create new array
T *temp = new T[this->capacity];
for (int i = 1; i < this->size; i++)
{
temp[i - 1] = this->data[i];
}
// Deallocate current array
delete[] this->data;
// Allocate new temp array
this->data = temp;
}
#endif
TEST FILE
#include <iostream>
#include "proj7-MyVector.h"
using namespace std;
int main()
{
cout << "MyVector Test" << endl;
cout << "Testing all functions using int MyVector, string MyVector, and double MyVector" << endl;
cout << endl;
cout << "Testing Default Constructor: ";
MyVector<int> intVector;
MyVector<string> stringVector;
MyVector<double> doubleVector;
cout << "Pass" << endl;
cout << "Testing pushFront: ";
intVector.pushFront(1);
stringVector.pushFront("test");
doubleVector.pushBack(1.32);
cout << "Pass" << endl;
cout << "Testing [] operator: ";
if (intVector[0] == 1 && stringVector[0] == "test" && doubleVector[0] == 1.32)
{
cout << "Pass" << endl;
}
else
{
cout << "Fail" << endl;
}
cout << "Testing pushBack: ";
intVector.pushBack(22);
stringVector.pushBack("hello");
doubleVector.pushBack(8.21);
cout << "Pass" << endl;
cout << "Testing back: ";
if (intVector.back() == 22 && stringVector.back() == "hello" && doubleVector.back() == 8.21)
{
cout << "Pass" << endl;
}
else
{
cout << "Fail" << endl;
}
cout << "Testing front: ";
if (intVector.front() == 1 && stringVector.front() == "test" && doubleVector.front() == 1.32)
{
cout << "Pass" << endl;
}
else
{
cout << "Fail" << endl;
}
cout << "Testing popFront: ";
int removedInt;
string removedString;
double removedDouble;
intVector.popFront(removedInt);
stringVector.popFront(removedString);
doubleVector.popFront(removedDouble);
if (removedInt == 1 && removedString == "test" && removedDouble == 1.32)
{
cout << "Pass" << endl;
}
else
{
cout << "Fail" << endl;
}
cout << "Testing getSize: ";
if (intVector.getSize() == 1 && stringVector.getSize() == 1 && doubleVector.getSize() == 1)
{
cout << "Pass" << endl;
}
else
{
cout << "Fail" << endl;
}
cout << "Testing popBack: ";
intVector.popBack(removedInt);
stringVector.popBack(removedString);
doubleVector.popBack(removedDouble);
if (removedInt == 22 && removedString == "hello" && removedDouble == 8.21)
{
cout << "Pass" << endl;
}
else
{
cout << "Fail" << endl;
}
cout << "Testing isEmpty: ";
if (intVector.isEmpty() && stringVector.isEmpty() && doubleVector.isEmpty())
{
cout << "Pass" << endl;
}
else
{
cout << "Fail" << endl;
}
cout << "Testing = operator: ";
for (int i = 0; i < 10; i++)
{
intVector.pushBack(i);
stringVector.pushBack("a");
doubleVector.pushBack(2.5);
}
MyVector<int> intVector2;
MyVector<string> stringVector2;
MyVector<double> doubleVector2;
intVector2 = intVector;
stringVector2 = stringVector;
doubleVector2 = doubleVector;
if (intVector2.front() == 0 && stringVector2.front() == "a" && doubleVector2.front() == 2.5)
{
cout << "Pass" << endl;
}
else
{
cout << "Fail" << endl;
}
cout << "Testing copy constructor: ";
MyVector<int> intVector3(intVector2);
MyVector<string> stringVector3(stringVector2);
MyVector<double> doubleVector3(doubleVector2);
if (intVector2.front() == 0 && stringVector2.front() == "a" && doubleVector2.front() == 2.5)
{
cout << "Pass" << endl;
}
else
{
cout << "Fail" << endl;
}
cout << "Testing erase: ";
intVector3.erase();
stringVector3.erase();
doubleVector3.erase();
if (intVector3.isEmpty() && stringVector3.isEmpty() && doubleVector3.isEmpty())
{
cout << "Pass" << endl;
}
else
{
cout << "Fail" << endl;
}
cout << "If all of the above pass, grow(), shiftRight() and shiftLeft() are assumed passing." << endl;
return 0;
}
template <class T>
MyVector<T> &MyVector<T>::operator=(const MyVector &v)
{
this->size = v.size;
this->capacity = v.capacity;
this->data = new T[this->capacity];
The previously allocated this->data gets leaked here. It's already allocated.
Furthermore, most of the class methods needlessly new a new temp buffer, copy data to it, and delete the old data and then replace it with the newly-allocated temp buffer.
This is needless work since, it looks like, most of these operations can be done in place. Furthermore, it appears that at least one of these has a bug that will result in memory corruption under certain conditions. In your shiftRight:
for (int i = 1; i < this->size + 1; i++)
{
temp[i] = this->data[i - 1];
}
This is going to assign something to temp[this->size]. If this->size happens to be equal to this->capacity, since temp is allocated to be this->capacity in size, this is going to result in a rather nasty demon flying out of your nose, since temp[this->size] does not exist.
Related
I am required to implement a dynamic array that adjusts, dynamically, in accordance with the number of value (temperatures) that are input into the code. I have written the majority of the code for this to be possible, however I have run into a bug and for the life of me, have been unable to locate the issue.
The program is supposed to output the values of temp_a, make temp_b = temp_a, output the value of temp_b, and then clear the value of temp_a, and finally output the values of temp_b once more.
However, when I compile the program, it outputs that the list is full and cannot add any more values, meaning there is a logic error somewhere in the code.
Please forgive me for the lengthy code, as soon as I can locate the error, the code shall be separated into multiple compilations.
#include <iostream>
using namespace std;
class TemperatureList {
private:
int* temp; // pointer to dynamic array
short current_size; // current number of elements
short max_size; // max number of elements allowed in this list
public:
// Overloading assignment operator
void operator =(const TemperatureList& another_list);
// === Constructors ===
// Default constructor
TemperatureList();
// Constructor that accepts an integer parameter that specifies the max length of the list
TemperatureList(int max);
// Copy constructor that accepts another List as parameter
TemperatureList(const TemperatureList& another_list);
// Destructor
~TemperatureList();
// === Modifier functions ===
// add new_value to end of list if there is still space
void add_temperature(int new_value);
// === Accessor functions ===
// return current current_size of the list
short get_current_size();
// === Other functions ===
// return the last element, or 0 if the list is empty, with a warning output
int get_last();
// return element at the position-th position, or 0 if the list is empty, with a warning output
int get_temp(short position);
// returns if current_size == 0
bool set_temp(short position, int value);
// returns if current_size == 0
bool empty();
// returns if current_size == max_size
bool full();
// Output list separated by commas
friend ostream& operator <<(ostream& outs, const TemperatureList& list);
};
int main() {
TemperatureList temp_a;
temp_a.add_temperature(23.5);
temp_a.add_temperature(24.6);
cout << temp_a;
TemperatureList temp_b = temp_a;
cout << temp_b;
temp_a = TemperatureList();
cout << "Now there's no temperatures in a.\n";
cout << temp_a;
cout << "How about temperatures in b?\n";
cout << temp_b;
return 0;
}
void TemperatureList::operator =(const TemperatureList& another_list) {
delete[] temp;
current_size = another_list.current_size;
max_size = another_list.max_size;
if (current_size > 0) {
temp = new int[max_size];
for (int i = 0; i < max_size; i++) {
temp[i] = another_list.temp[i];
}
}
else {
temp = NULL;
}
}
TemperatureList::TemperatureList() {
current_size = 0;
max_size = 0;
temp = NULL;
}
TemperatureList::TemperatureList(int max) : max_size(max) {
current_size = 0;
temp = new int[max];
}
TemperatureList::TemperatureList(const TemperatureList& another_list) {
current_size = another_list.current_size;
max_size = another_list.max_size;
if (current_size > 0) {
temp = new int[max_size];
for (int i = 0; i < max_size; i++) {
temp[i] = another_list.temp[i];
}
}
else {
temp = NULL;
}
}
TemperatureList::~TemperatureList() {
//cout << "== I am in destructor ==\n";
delete[] temp;
}
void TemperatureList::add_temperature(int new_value) {
if (current_size < max_size) {
temp[current_size] = new_value;
current_size++;
}
else {
cout << "Cannot add value to the list. It is full.\n";
}
}
int TemperatureList::get_last() {
if (empty()) {
cout << "The list is empty\n";
return 0;
}
else {
return temp[current_size - 1];
}
}
int TemperatureList::get_temp(short position) {
if (current_size >= position) {
return temp[position - 1];
}
else {
cout << "There is no temperature\n";
return 0;
}
}
bool TemperatureList::set_temp(short position, int value) {
if (current_size >= position) {
temp[position - 1] = value;
return true;
}
else {
return false;
}
}
short TemperatureList::get_current_size() {
return current_size;
}
bool TemperatureList::empty() {
return (current_size == 0);
}
bool TemperatureList::full() {
return (current_size == max_size);
}
ostream& operator <<(ostream& outs, const TemperatureList& list) {
int i;
for (i = 0; i < (list.current_size - 1); i++) {
outs << list.temp[i] << ",";
}
outs << list.temp[i];
return outs;
}
The logic error seems to stem from the fact that you initialize your current_size and max_size to zero. So, unless your run the overloaded constructor (wherein you’re set the max_size), every call to addTemperature() is going to fail the (current_size < max_size) check because they are both equal to zero.
before we get started, yes this is homework.
hopefully I can get some clarification here. I am implementing a priority queue with a fixed size array and have all the functions written and everything compiles but I am having a problem with the option M in the test file. All the other functions work just fine but when I try to add_multiple_items I get an expression error in the assert of the swap_with_parent function. here is my program files. The pqtest2.cpp file:
// FILE: pqtest2.cpp
// An interactive test program for the Priority Queue class
#include <cctype> // Provides toupper
#include <iostream> // Provides cout and cin
#include <cstdlib> // Provides EXIT_SUCCESS and size_t
#include "pqueue2.h" // Implemented using a heap
using namespace std;
// PROTOTYPES for functions used by this test program:
void print_menu( );
char get_user_command( );
int get_number(const char message[ ]);
void add_multiple_entries(PriorityQueue &q);
int main( )
{
PriorityQueue test;
char choice;
cout << "CSC-161 Lesson Ten Test Program" << endl << endl;
do
{
print_menu( );
choice = toupper(get_user_command( ));
switch (choice)
{
case 'E':
if (test.is_empty( ))
cout << "The Priority Queue is empty." << endl;
else
cout << "The Priority Queue is not empty." << endl;
break;
case 'G':
if (!test.is_empty( ))
cout << "Front item is: " << test.get_front( ) << endl;
else
cout << "There is no current item." << endl;
break;
case 'I':
test.insert(get_number("Please enter the next item: "),
(unsigned int) get_number("The item's priority: "));
break;
case 'M':
add_multiple_entries(test);
break;
case 'P':
test.print_tree("Contents of heap:");
break;
case 'S':
cout << "The size is " << test.size( ) << endl;
break;
case 'X':
if (test.is_empty( ))
cout << "The Priority Queue is empty." << endl;
else
while(!test.is_empty())
cout << "Value: " << test.get_front() << endl;
break;
case 'Q':
break;
default:
cout << choice << " is an invalid choice." << endl;
}
}
while ((choice != 'Q'));
return EXIT_SUCCESS;
}
void print_menu( )
{
cout << endl;
cout << "The following choices are available: " << endl;
cout << " E Print the result from the is_empty( ) function" << endl;
cout << " G Print the result from the get_front( ) function" << endl;
cout << " I Insert a new item with the insert(...) function" << endl;
cout << " M Add multiple items with varying priorities " << endl;
cout << " P Print the internal heap using the print_tree(...) function" << endl;
cout << " S Print the result from the size( ) function" << endl;
cout << " X Extract and print values in priority order" << endl;
cout << " Q Quit this test program" << endl;
}
char get_user_command( )
{
char command;
cout << "\nEnter choice: ";
cin >> command;
return command;
}
int get_number(const char message[ ])
{
int result;
cout << message;
cin >> result;
return result;
}
void add_multiple_entries(PriorityQueue &thisQueue)
{
thisQueue.insert(100, 10);
thisQueue.insert(200, 10);
thisQueue.insert(300, 5);
thisQueue.insert(400, 5);
thisQueue.insert(500, 20);
thisQueue.insert(600, 20);
thisQueue.insert(700, 20);
thisQueue.insert(800, 10);
thisQueue.insert(900, 10);
return;
}
The pqueue.h file:
// FILE: pqueue2.h
// CLASS PROVIDED: PriorityQueue (a priority queue of items)
//
// TYPEDEF and MEMBER CONSTANT for the PriorityQueue class:
// static const size_t CAPACITY = ______
// PriorityQueue::CAPACITY is the maximum number of entries that
// may be be in the priority queue at any one time.
//
// typedef _____ Item
// The type Item is the data type of the items in the Priority Queue.
// It may be any of the C++ built-in types (int, char, etc.), or a class
// with a default constructor, a copy constructor, and assignment operator.
//
// CONSTRUCTOR for the PriorityQueue class:
// PriorityQueue( )
// Postcondition: The PriorityQueue has been initialized with no Items.
//
// MODIFICATION MEMBER FUNCTIONS for the PriorityQueue class:
// void insert(const Item& entry, unsigned int priority)
// Postcondition: A new copy of entry has been inserted with the specified
// priority.
//
// Item get_front( )
// Precondition: size( ) > 0.
// Postcondition: The highest priority item has been returned and has been
// removed from the PriorityQueue. (If several items have equal priority,
// then there is no guarantee about which one will come out first!
// This differs from our first priority queue.)
//
// CONSTANT MEMBER FUNCTIONS for the PriorityQueue class:
// size_t size( ) const
// Postcondition: Return value is the total number of items in the
// PriorityQueue.
//
// bool is_empty( ) const
// Postcondition: Return value is true if the PriorityQueue is empty.
//
// VALUE SEMANTICS for the PriorityQueue class:
// Assignments and the copy constructor may be used with
// PriorityQueue objects
#ifndef PQUEUE_H
#define PQUEUE_H
#include <cstdlib> // Provides size_t
class PriorityQueue
{
public:
// TYPEDEF and MEMBER CONSTANT
typedef double Item;
static const size_t CAPACITY = 5000;
// CONSTRUCTOR
PriorityQueue( );
// MODIFICATION MEMBER FUNCTIONS
void insert(const Item& entry, unsigned int priority);
Item get_front( );
// CONSTANT MEMBER FUNCTIONS
size_t size( ) const { return many_items; }
bool is_empty( ) const { return (many_items == 0); }
// MEMBER FUNCTION FOR DEBUGGING
void print_tree(const char message[ ] = "", size_t i = 0) const;
private:
// STRUCT DEFINITION to store information about one item in the pqueue
struct OneItemInfo
{
Item data;
unsigned int priority;
};
// PRIVATE MEMBER VARIABLES
OneItemInfo heap[CAPACITY];
size_t many_items;
// PRIVATE HELPER FUNCTIONS -- see pqueue2.cxx for documentation
bool is_leaf(size_t i) const;
size_t parent_index(size_t i) const;
unsigned int parent_priority(size_t i) const;
size_t big_child_index(size_t i) const;
unsigned int big_child_priority(size_t i) const;
void swap_with_parent(size_t i);
};
#endif
The pqueue2.cpp file:
// FILE: pqueue2.cpp
// IMPLEMENTS: PriorityQueue (See pqueue2.h for documentation.)
// IMPLEMENTED BY: Michael Main (main#colorado.edu)
//
// Alex Chapman ID: S02084651
//
//
// INVARIANT for the PriorityQueue Class:
// 1. The member variable many_items is the number of items in the
// PriorityQueue.
// 2. The items themselves are stored in the member variable heap,
// which is a partially filled array organized to follow the usual
// heap storage rules from Chapter 11 of the class notes.
// NOTE: Private helper functions are implemented at the bottom of this
// file along with their precondition/postcondition contracts.
#include <cassert> // Provides assert function
#include <iostream> // Provides cin, cout
#include <iomanip> // Provides setw
#include <cmath> // Provides log2
#include "pqueue2.h"
using namespace std;
PriorityQueue::PriorityQueue( )
{
heap[CAPACITY];
many_items = 0;
}
void PriorityQueue::insert(const Item& entry, unsigned int priority)
{
if (many_items == 0)
{
heap[many_items].data = entry;
heap[many_items].priority = priority;
many_items++;
}
else
{
heap[many_items].data = entry;
heap[many_items].priority = priority;
unsigned int i = many_items;
many_items++;
while(parent_priority(i) < priority)
{
swap_with_parent(i);
i = parent_index(i);
}
}
}
PriorityQueue::Item PriorityQueue::get_front( )
{
assert(many_items > 0);
if (many_items == 1)
{
Item front_value = heap[0].data;
many_items--;
return front_value;
}
else
{
Item front_value = heap[0].data;
heap[0] = heap[many_items - 1];
unsigned int priority = heap[many_items - 1].priority;
unsigned int k = 0;
while((k < many_items) && !is_leaf(k) && big_child_priority(k) > priority)
{
unsigned int j = big_child_index(k);
swap_with_parent(big_child_index(k));
k = j;
}
many_items--;
return front_value;
}
}
bool PriorityQueue::is_leaf(size_t i) const
// Precondition: (i < many_items)
// Postcondition: If heap[i] has no children in the heap, then the function
// returns true. Otherwise the function returns false.
{
if (2 * i + 1 >= many_items)
{
return 1;
}
else
{
return 0;
}
}
size_t PriorityQueue::parent_index(size_t i) const
// Precondition: (i > 0) && (i < many_items)
// Postcondition: The return value is the index of the parent of heap[i].
{
return (i - 1) / 2;
}
unsigned int PriorityQueue::parent_priority(size_t i) const
// Precondition: (i > 0) && (i < many_items)
// Postcondition: The return value is the priority of the parent of heap[i].
{
return heap[(i - 1) / 2].priority;
}
size_t PriorityQueue::big_child_index(size_t i) const
// Precondition: !is_leaf(i)
// Postcondition: The return value is the index of one of heap[i]'s children.
// This is the child with the larger priority.
{
assert(!is_leaf(i));
if ((2 * i) + 2 < many_items)
{
if (heap[(2 * i) + 1].priority > heap[(2 * i) + 2].priority)
{
return (2 * i) + 1;
}
else
{
return (2 * i) + 2;
}
}
else
{
return (2 * i) + 1;
}
}
unsigned int PriorityQueue::big_child_priority(size_t i) const
// Precondition: !is_leaf(i)
// Postcondition: The return value heap[big_child_index(i)].priority
{
return heap[big_child_index(i)].priority;
}
void PriorityQueue::swap_with_parent(size_t i)
// Precondition: (i > 0) && (i < many_items)
// Postcondition: heap[i] has been swapped with heap[parent_index(i)]
{
assert (i>0 && i< many_items);
OneItemInfo temp_parent = heap[parent_index(i)];
OneItemInfo temp_child = heap[i];
heap[i] = temp_parent;
heap[parent_index(i)] = temp_child;
}
void PriorityQueue::print_tree(const char message[ ], size_t i) const
// Postcondition: If the message is non-empty, then that has been written
// to cout. After the message, the portion of the heap with root at node
// node i has been written to the screen. Each node's data is indented
// 4*d, where d is the depth of the node.
// NOTE: The default argument for message is the empty string, and the
// default argument for i is zero. For example, to print the entire
// tree of a PriorityQueue p, with a message of "The tree:", you can call:
// p.print_tree("The tree:");
// This call uses i=0, which prints the whole tree.
{
const char NO_MESSAGE[] = "";
size_t depth;
if (message[0] != '\0')
{
cout << message << endl;
}
if (i > many_items)
{
cout << "No Nodes" << endl;
}
else
{
depth = int(log(double(i + 1))/log(2.0));
cout << setw(depth * 4) << "";
cout << heap[i].data;
cout << " (priority " << heap[i].priority << ")" << endl;
if (2 * i + 1 < many_items)
{
print_tree(NO_MESSAGE, 2 * i + 1);
}
if (2 * i + 2 < many_items)
{
print_tree(NO_MESSAGE, 2 * i + 2);
}
}
}
Also I have attached the error pic.
while(parent_priority(i) < priority)
You kept looking for parent even when i == 0. Change it into while (i > 0 && parent_priority(i) < priority).
I am working on a project which I have to include a header file to my main.cpp. The header file is a heap which is using a template file. For reasons that escape me the insert and remove functions cannot be "seen" in the main file. I am getting an error message: C:/Users/Tito/Documents/C++proj/cs3304/Homework2_2/Homework10/main.cpp:58:17: error: request for member 'remove' in 'enter1', which is of non-class type 'priority_queue_heap()'. Can someone please tell me where I am going wrong? I will really appreciate it.
Thanks
Here are the lines of code:
Main.cpp:
/**
* Insert a few elements into a heap and the remove them
* one by one and see if we get them in the right.
*/
#include "priority_queue_heap.h"
#include "heap.h"
#include <iostream>
#include <ctime>
using namespace std;
int test1() {
heap<int> hp;
hp.insert(1);
hp.insert(2);
hp.insert(3);
hp.insert(4);
hp.insert(5);
hp.check_heap();
int x = hp.remove();
cout << "removed " << x << endl;
x = hp.remove();
cout << "removed " << x << endl;
x = hp.remove();
cout << "removed " << x << endl;
x = hp.remove();
cout << "removed " << x << endl;
x = hp.remove();
cout << "removed " << x << endl;
cout << "empty? " << hp.is_empty() << endl;
}
void test2() {
srand(time(NULL));
heap<int> hp;
for(int i = 0; i < 30; i++ ) {
hp.insert(rand());
}
while(!hp.is_empty()) {
int x = hp.remove();
cout << x << endl;
}
}
int main() {
/*test1();
test2();*/
priority_queue_heap<int> enter1();
enter1.insert(135);
enter1.insert(909);
enter1.insert(203);
cout<<endl;
cout<< "values to be removed" << endl;
cout << enter1.remove() << endl;
}
heap.h:
#ifndef HEAP_H
#define HEAP_H
/**
* This class implements a heap as described in the text.
* We will treat it as a priority queue.
*/
template <class T>
class heap {
public:
static const int CAPACITY = 10;
heap() {
size = 0;
}
bool is_empty() const { return size == 0;}
bool is_full() const { return size == CAPACITY; }
/**
* Remove the largest value from this heap and return it.
*
* Precondition: heap is not empty.
*/
T remove();
/**
* Inserts the 'value' into the heap.
*
* Precondition: heap is not full
*/
void insert(const T& value);
/**
* Check if the heap is valid.
* Prints out each parent and its children (for all nodes with children)
* Stops when a parent is less than one or both of its children
* Prints 'check' for each parent that is greater than or equal to its
children
*/
bool check_heap();
private:
T data[CAPACITY];
int size;
};
#include "heap.template"
#endif // HEAP_H
heap.template:
#include <cassert>
#include <cstdlib>
#include <iostream>
#include <iomanip>
/*
* parent index is p, children are at indices 2*p+1 and 2*p+2
* You must check that those are in range
*
* child index is c, parent index is (c-1)/2 (integer division)
*/
/**
* Inserts the 'value' into the heap.
*
* Precondition: heap is not full
*/
template <class T>
void heap<T>::insert(const T& value) {
assert(!is_full());
//std::cout << size << std::endl;
// add the value to a new node in proper position
data[size] = value;
size++;
// move the value up the tree as needed
int child = size-1; // index of the new 'node'
int parent = (child-1)/2; // index of the parent
while((child > 0) && (data[parent] < data[child])) {
// swap parent and child values
T tmp = data[parent];
data[parent] = data[child];
data[child] = tmp;
// update parent and child
child = parent; // this is where new value is!
parent = (child-1)/2;
}
// it's a heap!
}
/**
* Remove the largest value from this heap and return it.
*
* Precondition: heap is not empty.
*/
template <class T>
T heap<T>::remove() {
assert(!is_empty());
// grab first element, save it for return later
T save = data[0];
// copy last value in list to the beginning
// decrement size
data[0] = data[size-1];
size--;
// size--;
// data[0] = data[size];
// sift the new first element down until it finds its place
int parent = 0;
int left_child = 2*parent+1;
int right_child = 2*parent+2;
bool still_working = true;
while(still_working && left_child < size) { // while the parent has at
least one child
if(right_child >= size) {
// only the left child to worry about
if(data[parent] < data[left_child]) {
// out of order, so swap them
T t = data[parent];
data[parent] = data[left_child];
data[left_child] = t;
parent = left_child;
still_working = false; // we must be done!
} else {
still_working = false;
}
} else {
// two children
if(data[left_child] > data[right_child]) {
//left child larger
if(data[parent] < data[left_child]) {
// out of order, so swap them
T t = data[parent];
data[parent] = data[left_child];
data[left_child] = t;
parent = left_child;
} else {
still_working = false;
}
} else {
// right child larger
if(data[parent] < data[right_child]) {
// out of order, so swap them
T t = data[parent];
data[parent] = data[right_child];
data[right_child] = t;
parent = right_child;
} else {
still_working = false;
}
}
left_child = 2*parent + 1;
right_child = 2*parent + 2;
}
}
return save;
}
/**
* Check if the heap is valid.
* Prints out each parent and its children (for all nodes with children)
* Stops when a parent is less than one or both of its children
* Prints 'check' for each parent that is greater than or equal to its
children
*/
template <class T>
bool heap<T>::check_heap() {
for(int p = 0; p < size; p++ ) {
int cl = 2*p+1;
int cr = 2*p+2;
std::cout << std::setw(5) << p << std::setw(10) << data[p];
if(cl < size) { // p has a left child?
std::cout << std::setw(10) << data[cl];
if(data[p] < data[cl]) {
std:exit(1);
}
}
if(cr < size) { // p has a right child?
std::cout << std::setw(10) << data[cr];
if(data[p] < data[cr])
std::exit(1);
}
std::cout << std::endl;
}
return true;
}
priority_queue_simple.template:
#include <cassert>
/**
* Remove the largest value from this priority queue and return it.
*
* Precondition: priority queue is not empty.
*/
template <class T>
T priority_queue_simple<T>::remove() {
assert(size > 0);
int imax = 0;
for(int i = 1; i < size; i++ ) {
if(data[i] > data[imax])
imax = i;
}
T tmp = data[imax];
data[imax] = data[size-1];
size--;
return tmp;
}
/**
* Inserts the 'value' into the priority queue.
*
* Precondition: priority queue is not full
*/
template <class T>
void priority_queue_simple<T>::insert(const T& value) {
assert(size < CAPACITY);
size++;
data[size-1] = value;
}
priority_queue_heap.h:
#ifndef PRIORITY_QUEUE_HEAP_H
#define PRIORITY_QUEUE_HEAP_H
//#include "heap.h"
template <class T>
class priority_queue_heap {
priority_queue_heap();
bool is_empty() const;
bool is_full() const;
/**
* Remove the largest value from this priority queue and return it.
*
* Precondition: priority queue is not empty.
*/
T remove();
/**
* Inserts the 'value' into the priority queue.
*
* Precondition: priority queue is not full
*/
void insert(const T& value);
private:
heap<T> pri_que;
};
#include "priority_queue_heap.template"
#endif // PRIORITY_QUEUE_HEAP_H
template <class T>
T priority_queue_heap<T>::remove()
{
return pri_que.remove();
}
priority_queue_heap.template:
template <class T>
T priority_queue_heap<T>::remove()
{
return pri_que.remove();
}
template <class T>
void priority_queue_heap<T>::insert(const T& value)
{
pri_que.insert(value);
}
priority_queue_simple.h:
#ifndef PRIORITY_QUEUE_SIMPLE_H
#define PRIORITY_QUEUE_SIMPLE_H
/**
* This class implements a priority queue using a very simple strategy:
* Store the values in an array.
* Add new values at the end.
* When asked to remove a value, search for the largest (linear search)
*
*/
template <class T>
class priority_queue_simple {
public:
static const int CAPACITY = 30;
priority_queue_simple() {
size = 0;
}
bool is_empty() const {
return size == 0;
}
bool is_full() const {
return size == CAPACITY;
}
/**
* Remove the largest value from this priority queue and return it.
*
* Precondition: priority queue is not empty.
*/
T remove();
/**
* Inserts the 'value' into the priority queue.
*
* Precondition: priority queue is not full
*/
void insert(const T& value);
private:
T data[CAPACITY];
int size;
};
#include "priority_queue_simple.template"
#endif // PRIORITY_QUEUE_SIMPLE_H
You should remove the "()" characters after enter1 at line 51 of main.cpp ...
Otherwise c++ sees that as a function, it does not call the constructor.
You have a subtle error in your heap declaration (main.cpp:57):
priority_queue_heap<int> enter1();
Here you are actually declaring a prototype for the enter1 function that takes no argument and returns a priority_queue_heap<int>. Just remove the parentheses to actually declare a variable:
priority_queue_heap<int> enter1;
priority_queue_heap<int> enter1();
Is interpreted by the compiler as a function named enter1 that returns a priority_queue_heap<int> and takes no parameters. When you use
cout << enter1.remove() << endl;
You are trying to call a member function on a name that the compiler interpreted as a function so that is why it tells you it is of non class type. Remove the () from enter1 so you have
priority_queue_heap<int> enter1;
and now enter1 will be an object of type priority_queue_heap<int>
Basically a dynamic array, which has circular rotation when is full. You have access to every element and you can change it's value, however you can insert and remove only from both ends.(constant time). Most of the methods seem to be working fine, however at certain "push" numbers I get wrong output.
For example first input is 1,2,3 then I insert 4 at the end. Next output is: 2,3,4 However after I insert 5 at the end the output is 2, 3, 5
I have no idea what is causing this. I am posting the entire source code below (atleast the functions which have to do with the tests where the error must hide). There is some documentation in the file and an example of the error in case I haven't explained things clearly.
#include <iostream>
using namespace std;
template <typename Object>
class ArrayVector {
private:
int capacity; // capacity
int sz; // number of elements
Object* a;
int f; // start of the indexes
int b; // end of the indexes
public:
ArrayVector(int initCap);
~ArrayVector();
int size() const { return sz; }
bool isEmpty() const { return size() == 0; }
Object elemAtRank(int r);
void pushBack( const Object& e);
void pushFront(const Object& e);
void popBack();
void popFront();
};
template <typename Object> // constructor
ArrayVector<Object>::
ArrayVector(int initCap) {
capacity = initCap;
sz = 0;
a = new Object[capacity];
f = 0;
b = 0;
}
template <typename Object> // gets the element at a certain rank
Object ArrayVector<Object>:: elemAtRank(int r)
{
return a[(f + r) % sz]; // starting position in real array + r % number of elements
}
template <typename Object>
void ArrayVector<Object>:: pushBack( const Object& e)
{
if(sz == capacity && sz > 0) // if the array is full time to spin it
{
if(f == capacity){ // Handles the front.
f = 0; // if the front is equal to the capacity
// set it to zero, else increment
}else{
f++;
}
if(b == capacity){ //Handles the back
b = 0; //if the back is equal to the capacity
// cout<< "SC insert "<< e << " at "<< b <<endl;
a[b] = e;
}else{ // set it to zero, else increment
a[b] = e;
// cout<< "SC insert "<< e << " at "<< b <<endl;
b++;
}
}else{
a[b] = e;
// cout<< "insert "<< e << " at "<< b <<endl;
b++;
sz++;
}
}
template <typename Object>
void ArrayVector<Object>:: pushFront( const Object& e)
{
if(f == 0){
f = capacity-1;
}else{
f--;
}
a[f] = e;
if(sz< capacity)
sz++;
}
int main()
{
// Fill array and print it
cout << "Fill with numbers" << endl;
ArrayVector<int> asd(3);
asd.pushBack(1);
asd.pushBack(2);
asd.pushBack(3);
for(int i =0; i < asd.size(); i++)
cout << asd.elemAtRank(i) << endl;
//Test if it spins
cout << "BEGIN Spin TEST " << endl;
asd.pushBack(4);
cout << "First test is ok" << endl;
for(int i =0; i < asd.size(); i++)
cout << asd.elemAtRank(i) << endl;
// here the error comes
asd.pushBack(5);
cout << "On the second iteration things crash and burn" << endl;
for(int i =0; i < asd.size(); i++)
cout << asd.elemAtRank(i) << endl;
return 0;
}
In addition to your insertion times not matching your desired requirements, your issue is here:
template <typename Object>
void ArrayVector<Object>:: pushFront( const Object& e)
{
if(f == 0)
{
f = capacity-1;
}
else
{
f--;
}
a[f] = e; // problem lies here!
if(sz < capacity)
sz++;
}
You are figuring out where to do the insert, but you are not pushing the other elements around the vector; that is, you are just overwriting the element at the insertion point. If you wanted to push it onto the front, you would need to copy the other elements over 1 position each and then do your insert. A better solution (which would match your constant insertion time requirement) would be to implement it as a double-linked list. Pushing onto the ends would simply require the following pseudo-code:
void push_front(const Object& o)
{
if (size == capacity)
l.pop_back();
l.push_front(o);
}
If you really must use a contiguous memory block, you will not get constant-time insertion, but it would look like this:
// Assumptions: 0 is always the front, capacity-1 is always the maximum back
template <typename Object>
void ArrayVector<Object>:: pushFront( const Object& e)
{
// assume capacity > 0, move all the elements to the right one slot
for (int i = capacity - 1; i > 0; --i)
{
a[i] = a[i - 1];
}
a[0] = e;
if(sz < capacity)
sz++;
}
Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
This question does not appear to be about programming within the scope defined in the help center.
Closed 9 years ago.
Improve this question
I'm trying to port Artemis Componenty Entity System to C++ to learn a few things. However I'm stuck with a weird problem.
void addAll(ImmutableBagInterface<E>& items)
{
for(auto i = 0u; i < items.size(); ++i)
{
add(items.get(i));
}
}
This for loop goes infinitely even though it has a condition. The items.size() returns a valid value from what I've seen by printing it using cout. Also I've tried unsigned int and int instead of auto for the iterator however It hasn't changed a thing. I have no idea what is going on.
Heres all of the code for the "ImmutableBag"(which ain't really immutable since I'm using vectors but shhhh noone will know :P)
#ifndef IMMUTABLEBAG_H
#define IMMUTABLEBAG_H
#include <vector>
#include <iostream>
namespace artemis
{
template<class E>
class ImmutableBagInterface
{
public:
virtual ~ImmutableBagInterface(){};
virtual E get(int index) = 0;
virtual unsigned int size() = 0;
virtual bool isEmpty() = 0;
virtual bool contains(E e) = 0;
};
template<class E>
class Bag : public ImmutableBagInterface<E>
{
private:
std::vector<E> data;
void init(int capacity)
{
data.reserve(capacity);
}
public:
/**
* Constructs an empty Bag with an initial capacity of 64.
*
*/
Bag()
{
init(64);
}
/**
* Constructs an empty Bag with the specified initial capacity.
*
* #param capacity
* the initial capacity of Bag
*/
Bag(int capacity)
{
init(capacity);
}
/**
* Removes the element at the specified position in this Bag. does this by
* overwriting it was last element then removing last element
*
* #param index
* the index of element to be removed
* #return element that was removed from the Bag
*/
E remove(int index)
{
E e = data.at(index);
data.at(index) = data.back();
data.pop_back();
return e;
}
/**
* Remove and return the last object in the bag.
*
* #return the last object in the bag, null if empty.
*/
E removeLast()
{
if(!data.empty())
{
E e = data.back();
data.pop_back();
return e;
}
return nullptr;
}
/**
* Removes the first occurrence of the specified element from this Bag, if
* it is present. If the Bag does not contain the element, it is unchanged.
* does this by overwriting it was last element then removing last element
*
* #param e
* element to be removed from this list, if present
* #return <tt>true</tt> if this list contained the specified element
*/
bool remove(E e)
{
for(auto i = 0u; i < data.size(); i++)
{
E e2 = data.at(i);
if(e == e2)
{
data.at(i) = data.back();
data.pop_back();
return true;
}
}
return false;
}
/**
* Check if bag contains this element.
*
* #param e
* #return
*/
bool contains(E e)
{
for(auto &v : data)
{
if( e == v )
{
return true;
}
}
return false;
}
/**
* Removes from this Bag all of its elements that are contained in the
* specified Bag.
*
* #param bag
* Bag containing elements to be removed from this Bag
* #return {#code true} if this Bag changed as a result of the call
*/
bool removeAll(ImmutableBagInterface<E>& bag)
{
bool modified = false;
for(auto i = 0u; i < bag.size(); i++)
{
E e1 = bag.get(i);
for(auto j = 0u; j < data.size(); j++)
{
E e2 = data.at(j);
if(e1 == e2)
{
remove(j);
j--;
modified = true;
break;
}
}
}
return modified;
}
/**
* Returns the element at the specified position in Bag.
*
* #param index
* index of the element to return
* #return the element at the specified position in bag
*/
E get(int index)
{
return data.at(index);
}
const E get(int index) const
{
return data.at(index);
}
/**
* Returns the number of elements in this bag.
*
* #return the number of elements in this bag
*/
unsigned int size()
{
return data.size();
}
/**
* Returns the number of elements the bag can hold without growing.
*
* #return the number of elements the bag can hold without growing.
*/
int getCapacity()
{
return data.capacity();
}
/**
* Returns true if this list contains no elements.
*
* #return true if this list contains no elements
*/
bool isEmpty()
{
return data.empty();
}
/**
* Adds the specified element to the end of this bag. if needed also
* increases the capacity of the bag.
*
* #param e
* element to be added to this list
*/
void add(E e)
{
data.push_back(e);
}
/**
* Set element at specified index in the bag.
*
* #param index position of element
* #param e the element
*/
void set(unsigned int index, E e)
{
if(index >= data.size())
{
data.resize(index*2);
}
data.at(index) = e;
}
void grow()
{
int newCapacity = (data.capacity() * 3) / 2 + 1;
grow(newCapacity);
}
void grow(int capacity)
{
data.resize(capacity);
}
void ensureCapacity(int index)
{
if(index >= data.capacity())
{
data.resize(index * 2);
}
}
/**
* Removes all of the elements from this bag. The bag will be empty after
* this call returns.
*/
void clear()
{
data.clear();
}
/**
* Add all items into this bag.
* #param added
*/
void addAll(ImmutableBagInterface<E>& items)
{
for(auto i = 0u; i < items.size(); ++i)
{
add(items.get(i));
}
}
};
}
#endif // IMMUTABLEBAG_H
Here's a test where the issue occurs:
#include <iostream>
#include <string>
#include "ImmutableBag.h"
int main()
{
using namespace artemis;
Bag<std::string> bag;
Bag<std::string> bag2;
for(auto i = 0u; i < 20; i++)
{
bag2.add("Test");
}
bag2.add("Hello");
bag2.add("World");
bag.add("Hello");
std::cout << bag.get(0) << std::endl;
bag.add("World");
std::cout << bag.get(1) << std::endl;
for(auto i = 0u; i < bag2.size(); i++)
{
std::cout << bag2.get(i) << std::endl;
}
std::cout << "==========================" << std::endl;
bag2.removeAll(bag); //Executes normally (Removes all items, which are identical to any of the items in bag, from bag2)
for(auto i = 0u; i < bag2.size(); i++)
{
std::cout << bag2.get(i) << std::endl;
}
std::cout << "==========================" << std::endl;
bag.addAll(bag2); //Infinite loop... NOPE I was an idiot and wrote bag.addAll(bag) instead of bag.addAll(bag2)as Mike Seymour and Thynk Apps pointed out
for(auto i = 0u; i < bag.size(); ++i)
{
std::cout << bag.get(i) << std::endl;
}
return 0;
}
I don't know what your add() function is doing, but you do realize that if you add inside that loop to the container over which you are looping, you will increase its size by 1, so the for loop can (logically) never terminate? You will in all likelyhood run out of memory before that happens, though.