#include <iostream>
using namespace std;
class A{
int * p;
public:
A(){
cout << "Default Constructor" << endl;
p = new int[10]{0};
}
A(const A& obj){
cout << "Copy Constructor" << endl;
p = new int[10]{0};
for(int i=0;i<10;i++)
p[i] = obj.p[i];
}
A(A&& obj){
cout << "Move Constructor" << endl;
delete [] p;
p = obj.p;
obj.p = nullptr;
}
A& operator = (const A & obj){
cout << "Copy Assignment Operator " <<endl;
if(this == &obj)
return *this;
p = new int[10]{0};
for(int i = 0 ;i < 10;i++)
p[i] = obj.p[i];
return *this;
}
A& operator = (A&& obj){
cout << "Move Assignment Operator" <<endl;
if(this == &obj)
return *this;
delete [] p;
p = obj.p;
obj.p = nullptr;
return *this;
}
~A(){
cout << "Destructor " << endl;
delete [] p;
}
void setData(){
for(int i = 0 ; i < 10 ;i++)
p[i] = i*i;
}
void printData(){
for(int i=0;i<10;i++)
cout << p[i] << " ";
cout << endl;
}
};
int main()
{
A obj ;
obj.setData();
obj.printData();
A soj(std::move(obj));
soj.printData();
}
I am writing sample code and I am facing Following error , After checking through valgrind --track-origins=yes ./a.out
==1198431== Conditional jump or move depends on uninitialised value(s)
==1198431== at 0x1093BC: A::A(A&&) (in /home/pankaj/practice/PracticeC++Advanced/a.out)
==1198431== by 0x109233: main (in /home/alex/practice/PracticeC++Advanced/a.out)
==1198431== Uninitialised value was created by a stack allocation
==1198431== at 0x1091DA: main (in /home/alex/practice/PracticeC++Advanced/a.out)
How to Fixed the above error ?
Related
I have Memory Leak in my code and not sure how to diagnose it. There are 3 files and the main.cpp is the test file therefore cannot be altered. The program is using a Mem Checker and it displays that ==159804== Memcheck, a memory error detector, definitely lost: 280 bytes in 2 blocks.
Main.cpp (Cannot be altered)
#include<iostream>
#include<cstring>
#include"Basket.h"
#include"Basket.h" //intentional
using namespace std;
using namespace sdds;
void printHeader(const char* title)
{
char oldFill = cout.fill('-');
cout.width(40);
cout << "" << endl;
cout << "|> " << title << endl;
cout.fill('-');
cout.width(40);
cout << "" << endl;
cout.fill(oldFill);
}
int main()
{
sdds::Fruit fruits[]{
{"apple", 0.65},
{"banana", 1.25},
{"pear", 0.50},
{"mango", 0.75},
{"plum", 2.00},
};
{
printHeader("T1: Default Constructor");
Basket aBasket;
cout << aBasket;
// conversion to bool operator
if (aBasket)
cout << "Test failed: the basket should be empty!\n";
else
cout << "Test succeeded: operator said the basket is empty!\n";
cout << endl;
}
{
printHeader("T2: Custom Constructor");
Basket aBasket(fruits, 2, 6.99);
cout << aBasket;
// conversion to bool operator
if (aBasket)
cout << "Test succeeded: operator said the basket has content!\n";
else
cout << "Test failed: the basket should NOT be empty!\n";
cout << endl;
}
{
printHeader("T3: += operator");
Basket aBasket;
aBasket += fruits[2];
(aBasket += fruits[0]) += fruits[4];
aBasket.setPrice(12.234);
cout << aBasket;
cout << endl;
}
{
printHeader("T4: Copy Constructor");
Basket b1;
Basket b2(b1);
cout << "Basket #1 -> " << b1;
cout << "Basket #2 -> " << b2;
b1 += fruits[3];
b1.setPrice(3.50);
Basket b3(b1);
cout << "Basket #3 -> " << b3;
cout << endl;
}
{
printHeader("T5: Copy Assignment");
Basket b1, b2, b3(fruits, 5, 19.95);
b1 = b2;
cout << "Basket #1 -> " << b1;
cout << "Basket #2 -> " << b2;
b1 = b3;
cout << "Basket #1 -> " << b1;
b3 = b2;
cout << "Basket #3 -> " << b3;
}
return 0;
}
Basket.h
#ifndef Basket_h
#define Basket_h
#include <stdio.h>
#include <iomanip>
#include <iostream>
namespace sdds{
struct Fruit
{
char m_name[30 + 1];
double m_qty;
};
class Basket{
private:
Fruit *m_fruits;
int m_cnt;
double m_price;
public:
Basket();
Basket(Fruit* fruits, int cnt, double price);
Basket(Basket &d);
Basket& operator = (Basket &d);
~Basket();
void setPrice(double price);
operator bool() const;
Basket& operator+=(Fruit d);
friend std::ostream& operator << (std::ostream& output, Basket test);
};
}
#endif /* Basket_h */
Basket.cpp
#include "Basket.h"
using namespace sdds;
namespace sdds {
Basket::Basket(){
m_fruits = nullptr;
m_cnt = 0;
m_price = 0;
}
Basket::Basket(Fruit* fruits, int cnt, double price){
if (cnt > 0 && fruits != nullptr) {
m_cnt = cnt;
m_price = price;
m_fruits = new Fruit[cnt + 1];
for (int i = 0; i < cnt; i++) {
m_fruits[i] = fruits[i];
}
}else{
m_fruits = nullptr;
m_cnt = 0;
m_price = 0;
}
}
Basket::Basket(Basket &d){
m_price = d.m_price; // Shallow Copying
m_cnt = d.m_cnt;
m_fruits = new Fruit[m_cnt + 1];
for (int i = 0; i < m_cnt; i++) { // Deep Copying
m_fruits[i] = d.m_fruits[i];
}
}
Basket& Basket::operator = (Basket &d){
m_price = d.m_price;
m_cnt = d.m_cnt;
m_fruits = new Fruit[m_cnt + 1];
for (int i = 0; i < m_cnt; i++) {
m_fruits[i] = d.m_fruits[i];
}
return *this;
}
Basket::~Basket(){
delete [] m_fruits;
}
void Basket::setPrice(double price){
m_price = price;
}
Basket::operator bool() const {
// returning true if the Basket is valid
return m_fruits != nullptr;
}
Basket& Basket::operator+=(Fruit d){
Fruit* tmp = new Fruit[m_cnt + 1];
for (int i = 0; i < m_cnt; i++) {
tmp[i] = m_fruits[i];
}
tmp[m_cnt++] = d;
delete [] m_fruits;
m_fruits = tmp;
return *this;
}
std::ostream& operator << (std::ostream& output, Basket test){
if (test.m_cnt == 0 || test.m_price == 0 || test.m_fruits == nullptr) {
output << "The basket is empty!" << std::endl;
}else{
output << "Basket Content:" << std::endl;
std::cout << std::fixed;
std::cout << std::setprecision(2);
for (int i = 0 ; i < test.m_cnt; i++) {
output << std::setw(10) << test.m_fruits[i].m_name << ": " <<test.m_fruits[i].m_qty << "kg" << std::endl;
}
output << "Price: " << test.m_price << std::endl;
}
return output;
}
}
Your assignment operator leaks memory, since you failed to delete[] the original data when doing the assignment.
The easiest way to get a working assignment operator is to use the copy/swap idiom:
#include <algorithm>
//...
Basket& Basket::operator = (const Basket &d)
{
if ( &d != this)
{
Basket temp(d);
std::swap(temp.m_price, m_price);
std::swap(temp.m_cnt, cnt);
std::swap(temp.m_fruits, fruits);
}
return *this;
}
Your original assignment operator had multiple flaws:
Did not delete[] the old memory.
Did not do a check for self-assignment, thus Basket a; a = a; would fail.
Changed member variables before issuing a call to new[], thus an exception thrown would corrupt your object.
All three issues are taken care of with the code shown above.
In fact, item 2) need not be done for copy / swap to work (but done in the example code above, just to show what your original code was missing).
I need to include shallow copy constructor and I'm completely lost. I thought that the compiler provided a default shallow copy constructor but I have to provide one as well but I'm not sure how to write it. I tried writing it similar to the WrapArrayDeep copy constructor without the pointers but that didn't work. After altering the array both arrays for WrapArrayShallow should be empty.
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <string>
#pragma warning(disable: 4996)
using namespace std;
class WrapArrayDeep
{
public:
WrapArrayDeep()
{
capacity = 5;
pca = new char[capacity];
for(int i = 0;i < capacity;i++)
*(pca+i) = (97+i);
} //ends default constructor
WrapArrayDeep(const WrapArrayDeep& wad) //deep copy
{
capacity = wad.getCapacity();
pca = new char[capacity];
for (int i = 0;i < capacity;i++)
*(pca+i) = wad.pca[i];
} //ends copy constructor
~WrapArrayDeep()
{
cout << "destructor for WrapArrayDeep!\n";
delete [] pca;
} //ends destructor
void printArr()
{
for(int i = 0;i < capacity;i++)
cout << pca[i] << " ";
cout << endl;
} //ends print
void alterArr()
{
for(int i = 0;i < capacity;i++)
*(pca + i) = (123+i);
}
int getCapacity() const
{
return capacity;
}
WrapArrayDeep& operator =(const WrapArrayDeep& wad)
{
if(capacity != wad.capacity)
{
delete [] pca;
pca = new char[wad.capacity];
}
capacity = wad.capacity;
for(int i =0;i < capacity;i++)
pca[i] = wad.pca[i];
return *this;
} //end of = operator overload
private:
int capacity;
char *pca;
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class WrapArrayShallow
{
public:
WrapArrayShallow()
{
capacity = 5;
pca = new char[capacity];
for(int i = 0;i < capacity;i++)
pca[i] = (97+i);
} //ends default constructor
~WrapArrayShallow()
{
cout << "destructor for WrapArrayShallow!\n";
delete [] pca;
} //ends destructor
void printArr()
{
for(int i = 0;i < capacity;i++)
cout << *(pca + i) << " ";
}
void alterArr()
{
for(int i = 0;i < capacity;i++)
pca[i] = (123 + i);
}
int getCapacity() const
{
return capacity;
}
private:
int capacity;
char *pca;
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
int main()
{
//~~~~~~~~Part 1~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
cout << "Part 1\n";
int i = 7;
int *pi;
pi = &i;
cout << "i = " << i << endl << "pi = " << pi << endl << "*pi = " << *pi << endl;
cout << "address of i = " << &i << endl << "address of pi = " << &pi << endl;
int **ppi;
ppi = π
cout << "ppi = " << ppi << endl << "*ppi = " << *ppi << endl;
cout << "address of ppi = " << &ppi << endl << "**ppi = " <<**ppi <<endl;
cout << endl << "~~~~~~~~~~~~~~~~~~~~~~~~~~~";
//~~~~~~~~Part 2~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
cout << "\nPart 2\n";
cout << "This section instantiates a wrapper class for a dynamic array of 5 elements. \n";
WrapArrayDeep wad1, *wad2;
cout <<"WrapArray Deep 1\n";
wad1.printArr();
//deep copy of wad1
wad2 = new WrapArrayDeep(wad1);
cout << "WrapArrayDeep 2 ~ copy constructor \n";
wad2->printArr();
wad1.alterArr();
cout << "after altering WrapArrayDeep1, 1 and 2 = \n";
wad1.printArr();
wad2->printArr();
WrapArrayShallow was1, *was2;
cout << "WrapArrayShallow1\n";
was1.printArr();
//shallow copy of was1
was2 = new WrapArrayShallow(was1);
cout << "\nWrapArrayShallow2\n";
was2->printArr();
was1.alterArr();
cout << "\nafter altering WrapArrayShallow1, 1 and 2 = \n";
was1.printArr();
cout << endl;
was2->printArr();
cout << endl;
delete wad2;
delete was2;
cout << endl;
system("pause");
return 0;
}
To describe at the surface, Deep copy manages every variables including dynamically allocated one and safely copy to the destination object while the shallow copy don't care much about the dynamic variables. You might have a good read
here
When you copy a WrapArrayShallow, there are now two pointers pointing to the same array, and when either WrapArrayShallow is destroyed, you delete[] the array.
Your program exhibits undefined behaviour, it uses a pointer that has been invalidated, when the second WrapArrayShallow is destroyed, and you delete[] pca.
You need to co-ordinate between the different WrapArrayShallow objects such that the last survivor delete[]s the array when it is destroyed. The simplest way is to use a std::shared_ptr<char[]> instead of a char *
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;
}
I am writing to write a string class and while doing assignment operator overloading I am observing crash at the part where we do deletion of previously allocated memory. I tried to trace through code but couldn't figure it out. Any pointers would help
str& str::operator=(const str &Rhs)
{
if (this != &Rhs)
{
cout << " attempt of self allocation - " << endl;
**delete[] this->_element;** // crashes here
this->_capacity = Rhs._capacity;
this->_display = Rhs._display;
this->_size = Rhs._size;
if (Rhs._size > 0)
{
this->_element = new char(this->_size);
if (this->_element == NULL)
{
cout << " mem allocation failed " << endl;
}
}
for (int counter = 0; counter <= this->_size; counter++)
{
this->_element[counter] = Rhs._element[counter];
}
}
return *this;
}
/*copy constructor */
str::str(const str& Rhs)
{
// copy constructor called
this->_capacity = Rhs._capacity;
this->_display = Rhs._display;
this->_size = Rhs._size;
if (Rhs._size > 0)
{
this->_element = new char(_size);
if (this->_element == NULL)
{
cout << " mem allocation failed " << endl;
}
for (int counter = 0; counter <= this->_size; counter++)
{
this->_element[counter] = Rhs._element[counter];
}
}
}
/* constructor */
str::str(const char *Y)
{
cout << "constructor called !!! -- " << endl;
size_t len = this->stringlen(Y);
this->_element = new char(len + 1);
for (int counter = 0; counter < len; counter++)
{
this->_element[counter] = Y[counter];
}
this->_element[len] = '\0';
this->_size = len + 1;
cout << "string in constructor is -- " << this->_element << endl;
}
From .h file
class str
{
public:
/*Default Constructor*/
explicit str();
/*Constructor with single char Argument*/
explicit str(char x);
/*Constructor with char array Argument*/
explicit str(const char* Y);
/* Creating new element with copy constructor */
str(const str& Rhs);
/* Overloading of Assignment operator */
str& operator=(const str& Rhs);
friend int string_compare(const str& Lhs, const str& Rhs);
int reverse();
size_t stringlen(const char* Y);
str& operator+(str& Rhs);
bool operator==(const str& Rhs);
bool operator!=(const str& Rhs);
friend ostream& operator<<(ostream &out, str& Lhs);
private:
char* _element;
int _capacity;
bool _display;
int _size; //largest accessed + 1
};
Main Routine -
void test1() {
const char *j = "abc";
cout << "length of j = " << strlen(j) << endl;
str s1('U');
str s2("hello");
cout << s2 << endl;
s2.reverse();
cout << s2 << endl;
str s3(s2);
cout << s1 << endl;
cout << s2 << endl;
cout << s3 << endl;
**s2 = s1;** // crashes
cout << s2 << endl;
cout << s1 << endl;
}
There are several problems with your code.
The biggest one is: if you want to allocate an array you need to use new char[_size]. new char(_size) allocates one char with its value set to _size.
Second, once you fix that problem, you write past the end of your allocated array - judging by the comment in your header you need to allocate char[_size + 1].
Third, in your copy constructor you never initialize the _element array and in your assignment operator you never clear up the _element value. This will eventually lead to crash when you copy or assign an empty str and then try to assign to it (or at destruction time as I assume that the destructor also calls delete).
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 .