C++ overload () operator, lvalue and rvalue - c++

Consider the following simple class.
#include <iostream>
using namespace std;
class test
{
public:
int* myvar;
int sz;
test()
{
sz = 10;
myvar = new int[10];
}
void dump()
{
for(int i = 0; i < sz; i++)
{
cout << myvar[i] << " ";
}
cout << endl;
}
int& operator()(int index)
{
if(index >= sz)
{
int* newvar = new int[index+1];
for(int i = 0; i < sz; i++)
{
newvar[i] = myvar[i];
}
sz = index+1;
delete myvar;
myvar = newvar;
}
return myvar[index];
}
const int operator()(int index) const
{
if(index >= sz)
{
throw "index exceeds dimension";
}
else
{
return myvar[index];
}
}
};
It should behave like a dynamic array. I overloaded the () operator. My idea was, that for an assignment (lvalue), the upper version of the () will be called, and for a "read only" operation (rvalue) the lower version of () is used. The sample code should explain more clearly what I mean:
int main()
{
test x;
// will give 10 times zero
x.dump();
// assign some values
x(1) = 7;
x(9) = 99;
// will give
// 0 7 0 0 0 0 0 0 0 99
x.dump();
// should give 7
cout << x(1) << endl;
// should give 99
cout << x(9) << endl;
// this will increase the size of myvar to 15 elements and assign a value
x(15) = 15;
// this should give
// 0 7 0 0 0 0 0 0 0 99 0 0 0 0 0 15
x.dump();
// this should throw an exception because x(20) got never assigned a value!
// but instead of calling the lower version of operator() it also calls the
// upper, resulting in x being expanded now to 21 elements.
cout << x(20) << endl;
// will give 21 elements, instead of 16.
x.dump();
return 0;
}
So I access the contents of myvar via the () operator. It should be possible to assign a value just to any element, but it shall not be possible to query the value of an element that has never been set before. I thought by using different versions of (), one of which being const should suffice, but apparently, the compiler is always using the upper version of my operator, and never the lower. How can I fix this problem?
I read about the proxy object, e.g here, but I think this implementation will not work in my case because I am using an array. So
a) is it possible without the proxy, or if not
b) how should the proxy look like in my case?

So this is the solution I finally came up with (sort of):
#include <iostream>
using namespace std;
template <class T> class myclass
{
private:
unsigned numel;
T* elem;
public:
class proxy
{
private:
T*& elem;
unsigned& numel;
const unsigned index;
proxy(T*& elem, unsigned& numel, unsigned index) : elem(elem), numel(numel), index(index) { }
// didn't really need those two
// proxy(const proxy&) = default;
// proxy(proxy&&) = default;
friend class myclass;
public:
proxy& operator=(const T& value)
{
if(index >= numel)
{
cout << "assignment to an element outside the range!" << endl;
cout << "old size: " << numel << endl;
cout << "new size: " << index+1 << endl << endl;
T* newelem = new T[index+1];
for(unsigned i = 0; i <= index; i++)
{
if(i < this->numel)
{
newelem[i] = this->elem[i];
}
else
{
newelem[i] = 0;
}
}
if(this->elem != nullptr)
{
delete this->elem;
}
this->elem = newelem;
this->numel = index+1;
}
this->elem[index] = value;
return *this;
}
proxy& operator=(const proxy &other)
{
*this = (const T&)other;
return *this;
}
operator T&()
{
if(index >= numel)
{
cout << "cannot query the value of elements outside the range!" << endl;
cout << "# of elements: " << numel << endl;
cout << "index requested: " << index << endl << endl;
throw out_of_range("");
}
return elem[index];
}
operator const T&() const
{
if(index >= numel)
{
throw out_of_range("");
}
return elem[index];
}
};
myclass() : numel(0), elem(nullptr) {};
myclass(unsigned count)
{
this->numel = count;
this->elem = new T[count];
}
~myclass()
{
if(this->elem != nullptr)
{
delete this->elem;
}
}
friend ostream& operator<<(ostream& os, const myclass& mc)
{
os << endl;
for(unsigned i = 0; i < mc.numel; i++)
{
os << mc.elem[i] << " ";
os << endl;
}
os << endl;
return os;
}
proxy operator()(unsigned index)
{
return proxy(this->elem, this->numel, index);
}
};
int main()
{
myclass<double> my;
my(1) = 77;
my(0) = 200;
my(8) = 12;
cout << my;
try
{
cout << my(0) << endl;
cout << my(1) << endl;
cout << my(8) << endl;
cout << my(10) << endl;
}
catch(...)
{
cout << "error catched" << endl << endl;
}
my(10) = 10101;
cout << my(10) << endl;
}
the output on the terminal looks like this:
assignment to an element outside the range!
old size: 0
new size: 2
assignment to an element outside the range!
old size: 2
new size: 9
200
77
0
0
0
0
0
0
12
200
77
12
cannot query the value of elements outside the range!
# of elements: 9
index requested: 10
error catched
assignment to an element outside the range!
old size: 9
new size: 11
10101

Related

Homework task: Checking the equality of two arrays

I am stuck on a homework question which requires me to create/modify a function which will set two arrays equal to each other. The question asks:
"Use the copy assignment (=) operator to set the two arrays equal to each other, this can be checked with the following:
y = x;
cout << "x equals y? " << (x == y) << endl; //Should return "True"
And is set within the following rules:
"Note that two Array objects should be considered equal only if they have the same length and the same element values."
This is the code I have, I have implemented two debugging sections which shows that they are indeed equal both in the assignment function and the main function, so my best guess is that the lengths don't match up. I am not allowed to modify any of the code which was provided (All the class and function stuff, or anything above the debugger in main), so I'm not sure how to set the lengths equal to each other in order to satisfy the condition (x==y)
#include <iostream>
using namespace std;
// definition
#define MAX_LENGTH 100
#define INIT_VALUE 0
class Array {
public:
Array(int length);
Array& operator=(const Array& other);
int length() const;
int& operator[](int index);
bool operator==(const Array& other) const;
bool operator!=(const Array& other) const;
private:
int length_;
int elements_[MAX_LENGTH];
};
// implementation
Array::Array(int length) {
length_ = length;
if (length_ > MAX_LENGTH) length_ = MAX_LENGTH;
for (int i = 0; i < length_; ++i) {
elements_[i] = INIT_VALUE;
}
}
Array& Array::operator=(const Array& other)
{
/*DEBUG*/cout << endl << endl << "<<NOW IN ASSIGNMENT FUNCTION>>" << endl << endl;
for (int i = 0; i < other.length_; ++i)
{
elements_[i] = other.elements_[i];
/*DEBUG*/cout << endl << "Elements: " << elements_[i] << " | Other Elements: " << other.elements_[i] << endl;
}
return *this;
}
int Array::length() const {
return length_;
}
int& Array::operator[](int index) {
// Q3 code goes here
return elements_[index];
}
bool Array::operator==(const Array& other) const
{
if (length_ != other.length_) return false;
for (int i = 0; i < other.length_; ++i) {
if (elements_[i] != other.elements_[i]) return false;
}
return true;
}
bool Array::operator!=(const Array& other) const
{
if (length_ != other.length_)
{
return true;
}
for (int j = 0; j < other.length_; ++j)
{
if (elements_[j] != other.elements_[j]) return true;
}
return false;
}
// testing
int main()
{
Array x(10);
x[3] = 42;
cout << "x contains ";
for (int i = 0; i < x.length(); ++i) {
cout << x[i] << " ";
}
cout << endl;
Array y(5);
cout << boolalpha;
cout << "x equals y? " << (x == y) << endl;
cout << "x notequals y? " << (x != y) << endl;
y = x;
//DEBUG SECTION
cout << endl << endl << "<<NOW IN MAIN>>" << endl << endl;
for (int i = 0; i < x.length(); ++i)
{
cout << endl << "Elements: " << x[i] << " | Other Elements: " << y[i] << endl;
}
//END OF DEBUG SECTION
cout << "x equals y? " << (x == y) << endl;
}
So the question is, how can I get these arrays to have the same length without modifying them in 'main'? Can I do this through the assignment function?
You just forgot to assign the same length in the the Array::operator=.
This can be done by writing this->length_ = other.length_; in the
Array& Array::operator=(const Array& other) before overwriting the array.
As mentioned before, you did not asign the length correctly in the = operator.
Fix like this:
Array& Array::operator=(const Array& other)
{
length_ = other.length_;
for (int i = 0; i < length_; ++i)
{
elements_[i] = other.elements_[i];
}
return *this;
}
Also you can simplify your != operator drastically
bool Array::operator!=(const Array& other) const
{
return !(*this == other);
}
However, in my opinon even more important, you should also make use of the std-containers which allow dynamic sizes such as std::vector. This also would have avoided your bug.
In my opinion you should use these std-containers as soon as possible and get used to them. They are almost always the right choice when in doubt.
With std::vector your program could look like this:
#include <iostream>
#include <vector>
using namespace std;
// definition
#define INIT_VALUE 0
class Array {
public:
Array(int length);
Array& operator=(const Array& other);
int length() const;
int& operator[](int index);
bool operator==(const Array& other) const;
bool operator!=(const Array& other) const;
private:
std::vector<int> elements_;
};
// implementation
Array::Array(int length)
:
elements_(length, INIT_VALUE)
{
}
Array& Array::operator=(const Array& other)
{
/*DEBUG*/cout << endl << endl << "<<NOW IN ASSIGNMENT FUNCTION>>" << endl << endl;
elements_ = other.elements_;
return *this;
}
int Array::length() const {
return static_cast<int>(elements_.size());
}
int& Array::operator[](int index) {
// Q3 code goes here
return elements_[index];
}
bool Array::operator==(const Array& other) const
{
return elements_ == other.elements_;
}
bool Array::operator!=(const Array& other) const
{
return !(*this == other);
}
// testing
int main()
{
Array x(10);
x[3] = 42;
cout << "x contains ";
for (int i = 0; i < x.length(); ++i) {
cout << x[i] << " ";
}
cout << endl;
Array y(5);
cout << boolalpha;
cout << "x equals y? " << (x == y) << endl;
cout << "x notequals y? " << (x != y) << endl;
y = x;
//DEBUG SECTION
cout << endl << endl << "<<NOW IN MAIN>>" << endl << endl;
for (int i = 0; i < x.length(); ++i)
{
cout << endl << "Elements: " << x[i] << " | Other Elements: " << y[i] << endl;
}
//END OF DEBUG SECTION
cout << "x equals y? " << (x == y) << endl;
}

C++ Hamming Function

This program is supposed to create three arrays of class object My_array. The first array is filled with random numbers. The second array is an exact copy of the first. The third array is entered by the user. The program checks to make sure that the first two arrays indeed equal each other and then it check to the hamming distance of the first and third array. The professor defines the hamming distance as each part off the array that is different.
My problem has been getting hamming to work. I actually have a hard time with operating overloading so I am surprised that works (well I have no errors showing in VS Studio) but not the hamming part. Any help would be appreciated. There are three files in order: main.cpp, my_array.cpp, and my_array.h. Function definitions and declarations were provided by professor. I am required to insert how each function operates.
#include "my_array.h"
#include <iostream>
using namespace std;
int main()
{
int size;
cout << "How big of an array shall we work with? ";
cin >> size;
My_array a(size);
My_array b(size);
My_array c(size);
a.randomize(100);
b = a;
c.input();
cout << a << endl;
cout << b << endl;
cout << c << endl;
cout << "a != b: " << (a != b) << endl;
cout << "a == b: " << (a == b) << endl;
cout << "The hamming distance is: " << a.hamming(c);
return 0;
}
#include "my_array.h"
#include <iostream>
using namespace std;
#include <stdlib.h>
#include <time.h>
// Constructor
My_array::My_array(int the_size)
{
array = NULL;
size = 0;
resize(the_size);
}
// Destructor.
My_array::~My_array()
{
empty();
}
// Copy constructor
My_array::My_array(My_array &data)
: size(data.size)
{
array = new int[size];
for (int i = 0; i<size; i++)
array[i] = data.array[i];
}
// Overloaded assignment operator.
My_array &My_array::operator=(My_array &data)
{
if (this != &data) {
resize(data.size);
for (int i = 0; i<size; i++)
array[i] = data.array[i];
}
else
cout << "Attempt to copy an object on itself. "
<< "Operation ignored." << endl;
return *this;
}
void My_array::input()
{
int j;
cout << "Please enter " << size << " numbers.\n";
for (int i = 0; i < size; i++)
{
cout << "Number " << i + 1 << ": ";
cin >> j;
array[i] = j;
}
}
void My_array::randomize(int limit)
{
srand(time(NULL));
for (int i = 0; i < size; i++)
array[i] = rand() % limit + 1;
}
bool My_array::operator ==(My_array &data)
{
if(this->size != data.size)
return false;
for (int i = 0; i <size; i++)
{
if (*this[i].array != data.array[i])
return false;
}
return true;
}
bool My_array::operator !=(My_array &data)
{
if (*this == data)
return false;
return true;
}
int My_array::hamming(My_array &data)
{
int ham = 0;
for (int i = 0; i < size; i++)
if (*this[i].array != data[i].array)
ham++;
return ham;
}
// This function will empty the target object
void My_array::empty()
{
if (size != 0 && array != NULL) {
size = 0;
delete[] array;
}
}
// Resize the array.
void My_array::resize(int the_size)
{
if (size >= 0) {
empty();
if (the_size != 0) {
size = the_size;
array = new int[size];
}
}
else
cout << "Resize attepmted with a negative size. "
<< "Operation ignored." << endl;
}
// Access an element of the array.
int &My_array::operator[](int index)
{
if (index < size)
return array[index];
else {
cerr << "Illegal access to an element of the array." << endl
<< "The size of the array was " << size
<< " and the index was " << index << endl;
exit(1);
}
}
// Accessor
int My_array::get_size()
{
return size;
}
void My_array::output()
{
cout << "The array of size " << size
<< " contains the elements:" << endl;
for (int i = 0; i<size; i++)
cout << array[i] << ' ';
cout << endl;
}
//overloading the << operator.
ostream &operator<<(ostream &out, My_array &data)
{
out << "The array of size " << data.size
<< " contains the elements:" << endl;
for (int i = 0; i<data.size; i++)
out << data.array[i] << ' ';
out << endl;
return out;
}
#ifndef MY_ARRAY_H
#define MY_ARRAY_H
#include <iostream>
using namespace std;
class My_array {
protected:
int size;
int *array;
public:
// Constructor
My_array(int the_size = 0);
// Destructor
~My_array();
// Copy constructor
My_array(My_array &data);
// Assignment operator
My_array &operator=(My_array &data);
void input();
void randomize(int limit);
bool operator ==(My_array &data);
bool operator !=(My_array &data);
int hamming(My_array &data);
// Deletes the array
void empty();
// Resize the array.
void resize(int the_size = 0);
// Access an element of the array.
int &operator[](int index);
// Returns the size of the array.
int get_size();
// Output the elements of the array.
void output();
friend ostream &operator<<(ostream &out, My_array &data);
};
#endif
This:
*this[i].array != data[i].array
should be this:
array[i] != data.array[i]
or this:
array[i] != data[i]
The *this is unnecessary, and data[i] is a reference to an int (the same one you get by calling data.array[i], thanks to your operator[]), and an int has no member called "array".

C++ Cycle through the addresses of an object

Objects (that are not dynamic) are blocks of data in memory.
Is there a way to cycle through and print each item in an object?
I tried doing it with 'this' but I keep getting errors.
#include "stdafx.h"
#include <iostream>
#include "TestProject.h"
using namespace std;
class myclass {
int someint = 10;
double somedouble = 80000;
int somearray[5] = {0, 1, 2, 3, 4};
public:
void somefunction();
};
void myclass::somefunction() {
cout << "\n test \n" << this;
myclass *somepointer;
somepointer = this;
somepointer += 1;
cout << "\n test2 \n" << *somepointer;
//Error: no opperator '<<' matches these operands
}
int main() {
myclass myobject;
myobject.somefunction();
return 0;
}
I'm guessing the error is because the types don't match. But I can't really figure a solution. Is there a dynamic type, or do I have to test the type somehow?
You must add friend global std::ostream operator << to display content of object
#include "stdafx.h"
#include <iostream>
using namespace std;
class myclass {
int someint;
double somedouble;
int somearray[5];
public:
myclass()
{
someint = 10;
somedouble = 80000;
somearray[0] = 0;
somearray[1] = 1;
somearray[2] = 2;
somearray[3] = 3;
somearray[4] = 4;
}
void somefunction();
friend std::ostream& operator << (std::ostream& lhs, const myclass& rhs);
};
std::ostream& operator << (std::ostream& lhs, const myclass& rhs)
{
lhs << "someint: " << rhs.someint << std::endl
<< "somedouble: " << rhs.somedouble << std::endl
<< "somearray: { ";
for (int iIndex = 0; iIndex < 5; iIndex++)
{
if (iIndex == 4)
lhs << rhs.somearray[iIndex] << " }" << std::endl;
else
lhs << rhs.somearray[iIndex] << ", ";
}
return lhs;
}
void myclass::somefunction() {
cout << "\n test \n" << this;
myclass *somepointer;
somepointer = this;
somepointer += 1; // wrong pointer to object with `object + sizeof(object)` address,
// data probably has been corrupted
cout << "\n test2 \n" << *somepointer; // displaying objects content
}
int main() {
myclass myobject;
myobject.somefunction();
return 0;
}
as you want to get to the object member using its pointers shifts I post another program
#include "stdafx.h"
#include <iostream>
using namespace std;
#pragma pack (push, 1) // force data alignment to 1 byte
class myclass {
int someint;
double somedouble;
int somearray[5];
public:
myclass()
{
someint = 10;
somedouble = 80000;
somearray[0] = 0;
somearray[1] = 1;
somearray[2] = 2;
somearray[3] = 3;
somearray[4] = 4;
}
void somefunction();
friend std::ostream& operator << (std::ostream& lhs, const myclass& rhs);
};
#pragma pack (pop) // restore data alignment
std::ostream& operator << (std::ostream& lhs, const myclass& rhs)
{
lhs << "someint: " << rhs.someint << std::endl
<< "somedouble: " << rhs.somedouble << std::endl
<< "somearray: { ";
for (int iIndex = 0; iIndex < 5; iIndex++)
{
if (iIndex == 4)
lhs << rhs.somearray[iIndex] << " }" << std::endl;
else
lhs << rhs.somearray[iIndex] << ", ";
}
return lhs;
}
void myclass::somefunction() {
int* pSomeInt = (int*)this; // get someint address
double *pSomeDouble = (double*)(pSomeInt + 1); // get somedouble address
int* pSomeArray = (int*)(pSomeDouble + 1); // get somearray address
std::cout << "someint: " << *pSomeInt << std::endl
<< "somedouble: " << *pSomeDouble << std::endl
<< "somearray: { ";
for (int iIndex = 0; iIndex < 5; iIndex++)
{
if (iIndex == 4)
std::cout << pSomeArray[iIndex] << " }" << std::endl;
else
std::cout << pSomeArray[iIndex] << ", ";
}
}
int main() {
myclass myobject;
myobject.somefunction();
return 0;
}
C++, by design, has no reflection feature. This means there is no generic, type-independent way to acces type metadata (e.g. the list of members if a class and their types) at runtime. So what you're trying to do (if I understand it correctly) cannot be done in C++.
Also I'm not sure what you meant by "objects (that are not dynamic)". all objects are blocks of data in memory, regardless of whether they are dynamically allocated or not.

Changing an array class to hold a dynamic array

everything i have read says this should be easy and that you just add these three lines
typedef double* DoublePtr;
DoublePtr p;
p = new double [10]
but where do i add this code? Everything i have tried just breaks my program what am I missing? I tried a set function to set the value of max size but it didn't work either
does anyone know how to do this?
#include<iostream>
using namespace std;
const int MAX_SIZE = 50;
class ListDynamic
{
public:
ListDynamic();
bool full();
int getSize();
void addValue(double value);
double getValue(int index);
double getLast();
void deleteLast();
friend ostream& operator <<(ostream& out, const ListDynamic& thisList);
private:
double listValues[MAX_SIZE];
int size;
};
int main()
{
double value;
ListDynamic l;
cout << "size of List " << l.getSize() << endl;
cout << "New size of List " << l.getSize() << endl;
cout << "First Value: " << l.getValue(0) << endl;
cout << "Last Value: " << l.getLast() << endl;
cout << "deleting last value from list" << endl;
l.deleteLast();
cout << "new list size " << l.getSize() << endl;
cout << "the list now contains: " << endl << l << endl;
system("pause");
return 0;
}
ListDynamic::ListDynamic()
{
size = 0;
}
bool ListDynamic::full()
{
return (size == MAX_SIZE);
}
int ListDynamic::getSize()
{
return size;
}
void ListDynamic::addValue(double value)
{
if (size < MAX_SIZE)
{
listValues[size] = value;
size++;
}
else
cout << "\n\n*** Error in ListDynamic Class: Attempting to add value past max limit.";
}
double ListDynamic::getValue(int index)
{
if (index < size)
return listValues[index];
else
cout << "\n\n*** Error in ListDynamic Class: Attempting to retrieve value past current size.";
}
double ListDynamic::getLast()
{
if (size > 0)
return getValue(size - 1);
else
cout << "\n\n*** Error in ListDynamic Class: Call to getLast in Empty List.";
}
void ListDynamic::deleteLast()
{
if (size > 0)
size--;
else
cout << "\n\n*** Error in ListDynamic Class: Call to deleteLast in Empty List.";
}
ostream& operator <<(ostream& out, const ListDynamic& thisList)
{
for (int i = 0; i < thisList.size; i++)
out << thisList.listValues[i] << endl;
return out;
}
You need to change listValues to a double*
double* listValues;
And when you add a value greater than the size, you'll need to reallocate the array your array and copy the elements of the former array to the new one. For example:
void ListDynamic::addValue(double value)
{
if (full())
{
double* temp = new double[size];
std::copy(listValues, listValues + size, temp);
delete[] listValues;
listValues = new double[size + 1];
std::copy(temp, temp + size, listValues);
listValues[size] = value;
delete[] temp;
} else
{
listValues[size++] = value;
}
}

C++ Heap Corruption in Template array

As the title already says, I have a problem with a heap corruption in my C++ code.
I know there are a lot of topics that cover heap corruption problems, and I have visited a lot of them, I read up on a lot of sites about these matters and I've even used Visual Leak Detector to find the location of the memory leak. I still can't seem to figure out why I have a heap corruption.
My code:
#include <iostream>
#include "stdafx.h"
#include "cstdlib"
#include <vld.h>
#include <math.h>
using namespace std;
template <class T>
class PrioQueue
{
private:
int size_;
int tempIndex;
public:
T *bottom_;
T *top_;
PrioQueue(int n =20){
size_ = n;
bottom_ = new T[size_];
top_ = bottom_;
}
void push(T c){
//add the item to the list
*top_ = c;
top_++;
//Save the old stack values in the temp memory
T* values = bottom_;
T tempItem;
int index = num_items();
cout << "Num items: " << index << endl;
cout << "1" << endl;
while(index > 1){
cout << "2" << endl;
if(values[index-1] > values[index-2])
{
cout << "2b" << endl;
tempItem = values[index-2];
values[index-2] = c;
values[index-1] = tempItem;
}
cout << "3" << endl;
index--;
}
cout << "4" << endl;
}
// + operator
PrioQueue* operator+ (PrioQueue que2)
{
PrioQueue<T>* temp = new PrioQueue<T>();
cout << "Created temporary queue" << endl;
for(int i = 0; i <num_items(); i++)
{
cout << "Element in list: " << bottom_[i] << endl;
temp->push(bottom_[i]);
cout << "Temp is now: ";
temp->print();
}
for(int i = 0; i < que2.num_items(); i++)
{
cout << "Element in list: " << que2.bottom_[i] << endl;
temp->push(que2.bottom_[i]);
cout << "Temp is now: ";
temp->print();
}
cout << "Ran loop" << endl;
return temp;
}
// * operator
PrioQueue* operator* (PrioQueue que2)
{
PrioQueue<T>* temp = new PrioQueue<T>();
for(int i = 0; i < num_items(); i++)
{
for(int j = 0; j < que2.num_items(); j++)
{
if(bottom_[i] == que2.bottom_[j])
{
temp->push(bottom_[i]);
break;
}
}
}
return temp;
}
friend ostream& operator<< (ostream& output, PrioQueue& q) {
for(T *element = q.bottom_; element < q.top_; element++)
output << *element << " | ";
return output;
}
int num_items() {
return (top_ - bottom_ );
}
T pop(){
top_--;
return *top_;
}
int full() {
return (num_items() >= size_);
}
int empty() {
return (num_items() <= 0);
}
void print(){
cout << "Print function..." << endl;
cout << "Stack currently holds " << num_items() << " items: " ;
for (T *element=bottom_; element<top_; element++) {
cout << " " << *element;
}
cout << "\n";
}
~PrioQueue(){ // stacks when exiting functions
delete [] bottom_;
}
};
int main()
{
PrioQueue<int> *p1 = new PrioQueue<int>(20);
p1->push(5);
p1->push(2);
p1->push(8);
p1->push(4);
p1->print(); cout << "\n";
PrioQueue<int> *p2 = new PrioQueue<int>(5);
p2->push(33);
p2->push(66);
p2->push(8);
p2->push(5);
p2->print(); cout << "\n";
//add them together
p1->print();
p2->print();
((*p1) + (*p2))->print();
((*p1) * (*p2))->print();
PrioQueue<float> *f1 = new PrioQueue<float>(5);
f1->push(1.1f);
f1->push(5.2f);
f1->push(8.3f);
f1->push(14.4f);
f1->push(17.5f);
f1->print(); cout << "\n";
PrioQueue<float> *f2 = new PrioQueue<float>(4);
f2->push(2.2f);
f2->push(6.7f);
f2->push(10.3f);
f2->push(15.6f);
f2->print();
cout << "\n";
//add them together
((*f1) + (*f2))->print();
// Multiply them.
((*f1) * (*f2))->print();
cout << "\n";
cout << p1 << endl;
cout << f1 << endl;
cout << "Press any key to exit...";
cin.get();
cin.get();
delete p1;
delete p2;
delete f1;
delete f2;
return 0;
}
I already tried removing everything and start at the beginning.
It seemed that changing:
delete [] bottom_;
To:
delete bottom_;
Fixed it, but that was before I pushed a value to the array.
Could some of you please enlighten me on what is wrong. It would be very much appreciated.
Thank you in advance,
Greatings Matti Groot.
The change you mention leads to undefined behavior. If you got something with new[] you must pass it to delete[]. Plain delete is only good for what you got with plain new.
Your operator + and * creates new objects and return pointer to it. I don't see any attempt to delete those objects, so no wonder you have leaks. (It counts as bad design to return pointers-with-obligation for no good reason, even more so from operators on objects that should produce objects.)
1. Stop using new everywhere.
If you want a new Object to work with, create one on the stack.
PrioQueue *p1 = new PrioQueue(20); // NO!
PrioQueue q1(20); // YES!
2. Consider to use unsigned values where usigned values are appropriate.
3. In your operator+() you'll have to set the size of the new temporary Queue appropriately.
4. See Blastfurnace's answer regarding resource managment and operator design.
5. Try to find out what resource acquisition is initialization (RAII) is and use this knowledge.
I addressed some of your issues
template <class T>
class PrioQueue
{
private:
size_t size_;
T *bottom_;
T *top_;
public:
PrioQueue (void)
: size_(20U), bottom_(new T[20U]), top_(bottom_)
{
}
PrioQueue(size_t n)
: size_(n), bottom_(new T[n]), top_(bottom_)
{
}
PrioQueue(PrioQueue<T> const & rhs)
: size_(rhs.size_), bottom_(new T[rhs.size_]), top_(bottom_)
{
for (size_t i=0; i<size_; ++i)
{
bottom_[i] = rhs.bottom_[i];
}
}
PrioQueue<T> & operator= (PrioQueue<T> rhs)
{
swap(rhs);
}
void push (T c)
{
// check if its full
if (full()) throw std::logic_error("full");
//add the item to the list
*top_ = c;
top_++;
// there is no point operating on a new pointer named "values" here
// your still addressing the same memory, so you can just operate on bottom_ instead
for (size_t index = num_items()-1; index > 0; --index)
{
if(bottom_[index] > bottom_[index-1])
{
std::swap(bottom_[index], bottom_[index-1]);
}
}
}
// + operator
PrioQueue<T> operator+ (PrioQueue<T> const & que2)
{
// you need a temporary queue that is large enough
// so give it the proper size (sum of both sizes)
PrioQueue<T> temp(num_items() + que2.num_items());
std::cout << "Created temporary queue" << std::endl;
for(size_t i = 0; i <num_items(); i++)
{
std::cout << "Element in list: " << bottom_[i] << std::endl;
temp.push(bottom_[i]);
std::cout << "Temp is now: ";
temp.print();
}
for(size_t i = 0; i < que2.num_items(); i++)
{
std::cout << "Element in list: " << que2.bottom_[i] << std::endl;
temp.push(que2.bottom_[i]);
std::cout << "Temp is now: ";
temp.print();
}
std::cout << "Ran loop" << std::endl;
return temp;
}
// * operator
PrioQueue<T> operator* (PrioQueue<T> const & que2)
{
size_t que1_items = num_items(), que2_items = que2.num_items();
PrioQueue<T> temp(que1_items);
for (size_t i = 0U; i < que1_items; ++i)
{
for(size_t j = 0U; j < que2_items; ++j)
{
if(bottom_[i] == que2.bottom_[j])
{
temp.push(bottom_[i]);
}
}
}
return temp;
}
friend std::ostream& operator<< (std::ostream& output, PrioQueue<T> & q)
{
for(T *element = q.bottom_; element < q.top_; element++)
output << *element << " | ";
return output;
}
size_t num_items(void) const
{
return size_t(top_ - bottom_ );
}
T pop (void)
{
// you actually popped of the last element and returned the next
// i think it is likely you want to return the element you pop off
return *(top_--);
}
// why int? full or not is a rather boolean thing i guess
bool full (void) const
{
// num_items() > size_ must not happen!
return (num_items() == size_);
}
bool empty(void) const
{
// an unsigned type cannot be < 0
return (num_items() == 0);
}
void swap (PrioQueue<T> & rhs)
{
std::swap(size_, rhs.size_);
std::swap(bottom_, rhs.bottom_);
std::swap(top_, rhs.top_);
}
void print (void) const
{
cout << "Print function..." << endl;
cout << "Stack currently holds " << num_items() << " items: " ;
for (T * element=bottom_; element<top_; ++element)
{
cout << " " << *element;
}
cout << endl;
}
~PrioQueue()
{
delete [] bottom_;
}
};
int main()
{
PrioQueue<int> q1;
q1.push(5);
q1.push(2);
q1.push(8);
q1.push(4);
q1.print();
PrioQueue<int> q2;
q2.push(33);
q2.push(66);
q2.push(8);
q2.push(5);
q2.print();
std::cout << "Plus: " << std::endl;
PrioQueue<int> q_plus = q1+q2;
q_plus.print();
std::cout << "Multi: " << std::endl;
PrioQueue<int> q_multi = q1*q2;
q_multi.print();
}
Your class manages a resource (memory) but you don't correctly
handle copying or assignment. Please see: What is The Rule of
Three?.
The design of your operator+() and operator*() is unusual and
leaks memory. Returning PrioQueue* makes it cumbersome or
impossible to properly free temporary objects. Please see: Operator
overloading
You might be interested in The Definitive C++ Book Guide and List to learn the language basics and some good practices.
I suggest you try re-writing this without using new or delete. Change your * and + operators to return a PrioQueue. Change the PrioQueue to use a vector<T> instead of an array. You can then focus on writing your own priority queue. Make sure you use the standard priority queue if you actually need one though.
((*p1) + (*p2))->print();
and statements like these .. Your + & * operator returns a new'ed PrioQueue . So you are not deleting it anywhere .
So try to take return value in a temp PrioQueue pointer and call delete on it as well .