C++ Loop condition doesn't end the loop [closed] - c++

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.

Related

C++ Copy Constructor Results in Memory Error

so the code, basically an AList with multiple functions, I have below currently runs fine and my passes all assertions and test cases that are assigned to my assignment, however, I lose .5 points because of a memory error. I believe the error lies somewhere in my copy constructor, but I am currently struggling to know where is the issue.
This is how my code looks along with my copy constructor.
#ifndef __ALIST_H__
#define __ALIST_H__
// size should not be negative
typedef unsigned long size_t;
#define RFACTOR 2 // use factor 2
namespace ds {
template <typename ItemType> class TestDriver; // for autograding; please ignore
/** Array-based list. */
template <typename ItemType> class AList {
friend class TestDriver<ItemType>; // for autograding; please ignore
private:
/** The underlying array. */
ItemType *items;
/** Stores the current size of the list. */
size_t count;
/** Max number of items allowed. */
size_t maxCnt;
/** Resize the underlying array to the target capacity. */
void resize(size_t capacity) {
maxCnt = capacity;
ItemType *a = new ItemType[maxCnt];
for (size_t i = 0; i < count; i++) {
a[i] = items[i];
}
delete[] items;
items = a;
}
public:
/**
* Construct a new AList object.
*
* #param initSize initial size of the underlying array; default 100
*/
AList(size_t initSize = 100) {
count = 0;
maxCnt = initSize;
items = new ItemType[maxCnt];
}
/** Destroy the AList object. */
~AList() { delete[] items; }
/** Return the number of elements in list. */
size_t size() const { return count; }
/** Return the i-th item in list .*/
ItemType &get(int i) const { return items[i]; }
/** Append `x` to the end of list. */
void addLast(ItemType x) {
if (count == maxCnt) {
resize(count * RFACTOR);
}
items[count] = x;
count += 1;
}
/** Return the last item in list. */
ItemType &getLast() const { return items[count - 1]; }
/** Delete and return the last item. */
ItemType removeLast() {
ItemType returnItem = getLast();
count -= 1;
return returnItem;
}
AList(const AList<ItemType> &other);
void addFirst(ItemType x);
ItemType &getFirst() const;
ItemType removeFirst();
};
/** Copy constructor. */
template <typename ItemType>
AList<ItemType>::AList(const AList<ItemType> &other) {
// TODO: create a list that is identical to `other`
count = other.count;
maxCnt = other.maxCnt;
ItemType arr[maxCnt];
items = new ItemType[maxCnt];
for(size_t i = 0; i < count; i++)
{
items[i] = arr[i];
}
delete [] items;
items = other.items;
}
/** Insert x at the front of list. */
template <typename ItemType> void AList<ItemType>::addFirst(ItemType x) {
// TODO:
if(count == maxCnt)
{
resize(count * RFACTOR);
}
for(size_t i = count; i > 0; i--)
{
items[i] = items[i - 1];
}
items[0] = x;
count = count + 1;
}
/** Return the first element in list. */
template <typename ItemType> ItemType &AList<ItemType>::getFirst() const {
// TODO:
return items[0];
}
/** Delete and return the first element in list. */
template <typename ItemType> ItemType AList<ItemType>::removeFirst() {
// TODO:
ItemType temp = items[0];
for(size_t i = 0; i < count - 1; i++)
{
items[i] = items[i + 1];
}
count = count - 1;
return temp;
}
} // namespace ds
#endif // __ALIST_H__
When I run my code, this is what the memory error states:
Output: 'original list: [1]; copy & getFirst: 1; resulting list: [1]'
217Expected: 'original list: [1]; copy & getFirst: 1; resulting list: [1]'
218Error(s):
219==190== Invalid free() / delete / delete[] / realloc()
220==190== at 0x483D74F: operator delete[](void*) (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
221==190== by 0x10979A: ds::AList<int>::~AList() (AList.h:51)
222==190== by 0x10962E: main (test_driver.cpp:55)
223==190== Address 0x4da3cc0 is 0 bytes inside a block of size 4 free'd
224==190== at 0x483D74F: operator delete[](void*) (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
225==190== by 0x10979A: ds::AList<int>::~AList() (AList.h:51)
226==190== by 0x109608: main (test_driver.cpp:96)
227==190== Block was alloc'd at
228==190== at 0x483C583: operator new[](unsigned long) (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
229==190== by 0x109761: ds::AList<int>::AList(unsigned long) (AList.h:47)
230==190== by 0x10939F: main (test_driver.cpp:55)
231==190==
main program:
#define CATCH_CONFIG_MAIN
#include "AList.h"
#include "catch.hpp"
#include <cstdlib>
#define SIZE 5
TEST_CASE("All") {
ds::AList<int> L;
// randomly add SIZE ints to the array
int nums[SIZE];
srand(time(0)); // setting the seed for rand()
for (int i = 0; i < SIZE; i++) {
nums[i] = rand() % 20 + 1; // generating random numbers by rand()
L.addLast(nums[i]);
}
SECTION("copy constructor") {
ds::AList<int> *K = new ds::AList<int>(L);
CHECK(L.size() == K->size());
CHECK(K->getLast() == nums[SIZE - 1]);
delete K; // this should not also delete L
}
SECTION("addFirst") {
L.addFirst(123);
L.addFirst(234);
CHECK(L.getFirst() == 234);
CHECK(L.get(2) == nums[0]);
}
SECTION("removeFirst") {
int x = L.removeFirst();
CHECK(x == nums[0]);
CHECK(L.getLast() == nums[SIZE - 1]);
}
}
If anyone could give any tips or suggestions on how I can fix this, it would be greatly appreciated!

Locating C++ Memory Leak

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.

how do i implement heap data structure using c++? [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 5 years ago.
Improve this question
Using this simple example of a binary heap. How would i implement this data structure using c++ code.
1
/ \
3 6
/\ /\
5 9 8
Also apart from being able to gain easy access to the max or min values in an array, how is this data structure useful?
the example come from the following link: http://www.algolist.net/Data_structures/Binary_heap
Here is my simplest C++ implementation for heap. The code is well-commented.
/*
Usage:
heap Heap;
Heap.clear();
Heap.insert(value);
Heap.remove();
Heap.print();
*/
struct heap {
int myarray[NN+1]; // myarray to store the numbers as heap, 1 indexed
int n; // the number of nodes in my array
heap() { // constructor
clear(); // we clear the heap
}
void clear() { // initialize the heap
n = 0; // initially there are no nodes in the heap
}
void insert( int K ) { // inserting an element K in the heap
if( n == NN ) { // the heap is full
printf("cannot insert any more element, the heap is full\n");
return;
}
++n; // so, we have a new element, we increased n before adding
// the element because we start from index 1
myarray[n] = K; // inserted the element at the rightmost position
int p = n; // for keeping the current position
while( p > 1 ) { // p = 1 means we are on the root, and its a heap
int pr = p / 2; // pr is the parent of p
if( myarray[pr] > myarray[p] ) { // parent is greater than child
swap( myarray[pr], myarray[p] );
p = pr; // now the new position of the current element is pr
} else break; // otherwise its a heap, so we can stop here
}
}
int remove() { // removing the minimum element from the heap
if( n == 0 ) { // is the heap is empty
printf("The heap is empty, cannot delete.\n");
return -1;
}
int K = myarray[1]; // first element in the heap is the minimum
myarray[1] = myarray[n]; // brought the last element in 1st position
n--; // as we removed one element, now we need to maintain the heap
int p = 1; // as we moved the rightmost element in index 1
while( 2 * p <= n ) { // means p has at least one child, if 2*p > n
// we are sure that p is in the last level
int ch = 2 * p; // contains the index of the child
if( 2 * p + 1 <= n ) { // right child exists
if( myarray[ch] > myarray[ch+1] ) // right child is smaller
// than left child
ch++; // ch contains the index of the right child
}
if( myarray[p] > myarray[ch] ) { // so, current node is larger
// than its child
swap( myarray[p], myarray[ch] );
p = ch; // new position of the current element
} else break; //current node is smaller than its children, so heap
}
return K; // as we stored the minimum element in K
}
void print() { // printing the heap
printf("Number of elements: %d\n", n);
for( int i = 1; i <= n; i++ ) printf("%d ", myarray[i]);
printf("\n");
}
// Time: O(nlogn)
// Extra space: O(1) as we will pass the input array as res here
void heapSort(int* res) {
for(int i = 0, len = n; i < len; ++i) {
res[i] = remove();
}
}
};
I am writing below Java implementation it can help you to write code in c++;
import java.util.Arrays;
/**
* Min heap implementation, also caters to duplicate
*/
public class MinHeap {`
private int capacity = 10;
private int size;
int[] items;
public MinHeap() {
items = new int[capacity];
size = 0;
}
public void ensureExtraCapacity() {
if (size == capacity) {
items = Arrays.copyOf(items, capacity * 2);
capacity *= 2;
}
}
private int getLeftChildIndex(int index) {
return 2 * index + 1;
}
private int getRightChildIndex(int index) {
return 2 * index + 2;
}
private int getParentIndex(int index) {
return (index - 1) / 2;
}
private boolean hasLeftChild(int index) {
return size > getLeftChildIndex(index);
}
private boolean hasRightChild(int index) {
return size > getRightChildIndex(index);
}
private boolean hasParent(int index) {
if(index == 0)
return false;
return getParentIndex(index) >= 0;
}
private int leftChild(int index) {
return items[getLeftChildIndex(index)];
}
private int rightChild(int index) {
return items[getRightChildIndex(index)];
}
private int parent(int index) {
return items[getParentIndex(index)];
}
private void swapValues(int index1, int index2) {
int temp = items[index1];
items[index1] = items[index2];
items[index2] = temp;
}
public int peek() {
if (size == 0) throw new IllegalStateException();
return items[0];
}
public int poll() {
if (size == 0) throw new IllegalStateException();
int polled = items[0];
items[0] = items[size - 1];
size--;
heapifyDown();
return polled;
}
public void add(int item) {
ensureExtraCapacity();
items[size] = item;
size++;
heapifyUp();
}
private void heapifyUp() {
int index = size - 1;
while (hasParent(index) && parent(index) > items[index]) {
swapValues(index, getParentIndex(index));
index = getParentIndex(index);
}
}
private void heapifyDown() {
int index = 0;
while (hasLeftChild(index)) {
int minimumChildIndex = getLeftChildIndex(index);
if (hasRightChild(index) && rightChild(index) < leftChild(index))
minimumChildIndex = getRightChildIndex(index);
if (items[index] < items[minimumChildIndex]) {
break;
} else {
swapValues(index, minimumChildIndex);
}
index = minimumChildIndex;
}
}
/* public void printMinHeap() {
while (size > 0) {
int poll = poll();
System.out.println(poll);
}
}*/
/* public static void main(String[] args) {
MinHeap minHeap = new MinHeap();
minHeap.add(7);
minHeap.add(3);
minHeap.add(4);
minHeap.add(10);
minHeap.add(1);
minHeap.add(15);
minHeap.add(2);
minHeap.add(17);
minHeap.add(1);
minHeap.printMinHeap();
}*/
}

Not able to access functions from object

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>

Extending std::vector as an dynamic array with NULL objects

As the title says, I try to extend the std::vector class in that way if I erase an element, the value of the position is not erased but actually set to NULL (providing a gap).
template<typename T>
class FVector : public std::vector<T> {
typedef std::vector<T> Base;
protected:
/** The number of elements in the vector */
size_t elementCount;
/**
* The index of the last element. This field is actually vector's length.
* For example when you have a vector like this ["a","b","c"] then the
* elementCount would be 3 and lastIndex would be 2 (because indexes are
* zero-based). But if you erased two first elements,
* leaving [null, null, "c" ] then elementCount=1 (because there is only
* one element in the vector!) however lastIndex would still remain 2.
* After you erase "c" lastIndex would be set to -1 (so it's enough to
* add 1 to lastIndex to determine vector's length.
*/
int lastIndex;
private:
/**
* Returns the index of the last not-null element in the vector,
* starting from position position downwards.
*
* #param position the position from which counting is to be begun.
* #return last element before (or on) index <code>position</code>
*/
int FindLastIndex(int position) {
int nLastItem = position;
if (position < 0) {
return -1;
}
for (; nLastItem >= 0; nLastItem--) {
if (Base::operator[](nLastItem) != NULL) {
break;
}
}
return (nLastItem);
}
public:
FVector(const T & value = T())
: elementCount(0), lastIndex(-1) {
}
FVector(int initialCapacity, const T & value = T())
: elementCount(0), lastIndex(-1),
std::vector<T>(initialCapacity, value) {
}
size_t Capacity() const {
return Base::size();
}
size_t Size() const {
return elementCount;
}
int LastIndex() const {
return lastIndex;
}
void AddElement(const T& obj) {
Base::push_back(obj);
elementCount++;
lastIndex++;
}
T & ElementAt(int index) {
if (index > lastIndex) {
// error
}
return Base::at(index);
}
void EraseElementAt(int index) throw() {
if (index > lastIndex) {
std::stringstream ss;
ss << index << " > " << lastIndex;
throw ArrayIndexOutOfBoundsException(ss.str());
}
if (Base::operator[](index) != NULL) {
elementCount--;
T v = Base::at(index);
delete v;
Base::at(index) = NULL;
if (index == lastIndex) {
lastIndex = FindLastIndex(lastIndex - 1);
}
}
}
};
It is not working like I expect. When I call the erase() method on an element the element
is not set to NULL.
For example:
class Int {
int i;
public:
Int(int v): i(v) { };
~Int() { }
};
//...
FVector<Int *> * v = new FVector<Int *>();
v->AddElement(new Int(1));
v->AddElement(new Int(3));
v->AddElement(new Int(5));
v->EraseElementAt(0);
v->EraseElementAt(2);
// ...
delete v;
will result in
[null, 3]
but I expect it to be
[null, 3, null]
Well, I do not know if that is possible what I try to achieve. I thought taking the std::vector class, which is a dynamic array (so why should I write my own array class then) give me all the basics I need to implement such thing.
Can anybody shed some light on that, I think I have some implementation issues here.
Thanks for your help!
In your EraseElementAt you have this:
if (index == lastIndex) {
lastIndex = FindLastIndex(lastIndex - 1);
}
If you happen to erase the last element in the vector (which you did) it will shorten the vector (decrement lastIndex). It seems like you want your vector to not do this - rather you are wanting the vector to null but not shorten. Maybe just take this out.