C++ Deep and Shallow Copy - c++

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 *

Related

Wrong output for an array of a class

So, I have been provided the following classes along with the member variables and methods ( the constructors included . NO extra variables and methods should be added ). I wrote the following codes for the methods provided:
Container Class
# define INTEGER 1
# define INT_ARRAY 2
# define INT_MATRIX 3
class Container{
int *value;
int *valueArray;
int **valueMatrix;
int firstDim, secondDim;
int storedType;
void reset(){
if (value != NULL){
delete value;
value=NULL;
}
if (valueArray != NULL){
delete[] valueArray;
valueArray=NULL;
}
if (valueMatrix != NULL){
for(int i=0;i<firstDim;i++){
delete[] valueMatrix[i];
}
delete[] valueMatrix;
valueMatrix=NULL;
}
firstDim = 0;
secondDim = 0;
storedType = -1;
}
public:
Container(){
cout << "Constructing Container with empty parameter" << endl;
cout << "___________________________________________" << endl;
value = NULL;
valueArray = NULL;
valueMatrix = NULL;
firstDim = 0;
secondDim = 0;
storedType = -1;
}
Container (int val){
cout << "Constructing Container with a single integer parameter" << endl;
cout << "______________________________________________________" << endl;
value=new int(val);
valueArray = NULL;
valueMatrix = NULL;
firstDim = 0;
secondDim = 0;
storedType = INTEGER;
}
Container (int *valArr, int len){
cout << "Constructing Container with integer array parameter" << endl;
cout << "___________________________________________________" << endl;
valueArray=new int[len];
value=NULL;
valueMatrix=NULL;
for(int i=0;i<len;i++) valueArray[i]=valArr[i];
firstDim = len;
secondDim = 0;
storedType = INT_ARRAY;
}
Container (int **valMat, int r, int c){
cout << "Constructing Container with integer matrix parameter" << endl;
cout << "____________________________________________________" << endl;
valueMatrix=new int*[r];
value=NULL;
valueArray=NULL;
for(int i=0;i<r;i++){
valueMatrix[i]=new int[c];
for(int j=0;j<c;j++){
valueMatrix[i][j]=valMat[i][j];
}
}
firstDim=r;
secondDim=c;
storedType=INT_MATRIX;
}
Container(const Container &obj){
cout << "Calling copy constructor of Container" << endl;
cout << "_____________________________________" << endl;
firstDim=obj.firstDim;
secondDim=obj.secondDim;
storedType=obj.storedType;
value=new int;
value=obj.value;
valueArray=new int[firstDim];
valueArray=obj.valueArray;
valueMatrix=new int*[firstDim];
for(int k=0;k<obj.firstDim;k++){
valueMatrix[k]=new int[secondDim];
}
valueMatrix=obj.valueMatrix;
}
void setItem (int val){
reset();
value=new int(val);
firstDim = 0;
secondDim = 0;
storedType = INTEGER;
valueArray=NULL;
valueMatrix=NULL;
}
void setItem(int *valArr, int len){
reset();
valueArray=new int[len];
for(int i=0;i<len;i++) valueArray[i]=valArr[i];
firstDim = len;
secondDim = 0;
storedType = INT_ARRAY;
value=NULL;
valueMatrix=NULL;
}
void setItem(int **valMat, int r, int c){
reset();
valueMatrix=new int*[r];
for(int i=0;i<r;i++){
valueMatrix[i]=new int[c];
for(int j=0;j<c;j++){
valueMatrix[i][j]=valMat[i][j];
}
}
firstDim=r;
secondDim=c;
storedType=INT_MATRIX;
value=NULL;
valueArray=NULL;
}
void * getItem(){
if (value != NULL) return value;
if (valueArray != NULL) return valueArray;
if (valueMatrix != NULL) return valueMatrix;
return NULL;
}
int getFirstDim(){
return firstDim;
}
int getSecondDim(){
return secondDim;
}
int getStoredType(){
return storedType;
}
void print(){
if (value != NULL){
cout << "There is only an integer value in the container object" << endl;
cout << "The value is: " << *value << endl;
}
else if (valueArray != NULL){
cout << "There is an integer array in the container object" << endl;
cout << "The values stored in the array are:" << endl;
for (int i=0; i<firstDim; i++){
cout << valueArray[i] << " ";
}
cout << endl;
}
else if (valueMatrix != NULL){
cout << "There is an integer matrix in the container object" << endl;
cout << "The values stored in the matrix are:" << endl;
for (int i=0; i<firstDim; i++){
for (int j=0; j<secondDim; j++){
cout << valueMatrix[i][j] << " ";
}
cout << endl;
}
}
else{
cout << "The object has no elements" << endl;
}
}
~Container(){
if (value != NULL){
cout << "Freeing allocated memory for a single integer" << endl;
delete value;
value = NULL;
}
if (valueArray != NULL){
cout << "Freeing allocated memory for integer array" << endl;
delete[] valueArray;
valueArray = NULL;
}
if (valueMatrix != NULL){
cout << "Freeing allocated memory for integer matrix" << endl;
for(int i=0;i<firstDim;i++){
delete[] valueMatrix[i];
}
delete[] valueMatrix;
valueMatrix = NULL;
}
firstDim = 0;
secondDim = 0;
storedType = -1;
cout << "_____________________" << endl;
cout << "Destructing Container" << endl;
}
};
ContainerArray Class
class ContainerArray{
Container *arrayOfContainers;
int allocatedSize;
public:
ContainerArray(){
allocatedSize = 0;
arrayOfContainers = NULL;
}
ContainerArray(int size){
allocatedSize=size;
arrayOfContainers=new Container[size];
}
void setAllocatedSize(int sz){
if(allocatedSize){
delete[] arrayOfContainers;
}
allocatedSize=sz;
arrayOfContainers=new Container[sz];
}
int getAllocatedSize(){
return allocatedSize;
}
Container getItemAt(int index){
if (index >= allocatedSize){
cout << "Cannot get item, Exception: Container Array index out of bound";
exit(0);
}
return arrayOfContainers[index];
}
void setItemAt(Container p,int x){
if(x >= allocatedSize) cout << "Exception: Container Array index out of bound";
else{
if(p.getStoredType() == 1) arrayOfContainers[x].setItem(*(int*)p.getItem());
else if(p.getStoredType() == 2) arrayOfContainers[x].setItem((int*)p.getItem(),p.getFirstDim());
else if(p.getStoredType() == 3) arrayOfContainers[x].setItem((int**)p.getItem(),p.getFirstDim(),p.getSecondDim());
}
}
~ContainerArray(){
delete[] arrayOfContainers;
allocatedSize=0;
arrayOfContainers=NULL;
}
};
main() function
int main()
{
Container a;
Container b(100);
int *arr = new int[3];
arr[0] = 10;
arr[1] = 20;
arr[2] = 30;
Container c(arr, 3);
int **mat = new int*[2];
mat[0] = new int[3];
mat[0][0] = 1;
mat[0][1] = 2;
mat[0][2] = 3;
mat[1] = new int[3];
mat[1][0] = 4;
mat[1][1] = 5;
mat[1][2] = 6;
Container d(mat, 2, 3);
int firstObjArraySize = 3, secondObjArraySize = 4;
ContainerArray containerArray1;
ContainerArray containerArray2(secondObjArraySize);
cout << secondObjArraySize << " constructors with empty parameters are called" << endl;
containerArray1.setAllocatedSize(firstObjArraySize);
cout << firstObjArraySize << " constructors with empty parameters are called" << endl;
containerArray1.setItemAt(a, 0);
containerArray1.setItemAt(b, 2);
containerArray1.setItemAt(c, 1);
containerArray2.setItemAt(c, 0);
containerArray2.setItemAt(d, 1);
for (int i=0; i<3; i++){
cout << i << "-th element of 1st container array:" << endl;
containerArray1.getItemAt(i).print();
}
for (int i=0; i<2; i++){
cout << i << "-th element of 2nd container array:" << endl;
containerArray2.getItemAt(i).print();
}
return 0;
}
The Problem:
The object containerArray1 prints well . But the array initialized in the main() function is used again in the object containeraArray2 . Due to the destructor freeing the memory of the previous object , the array's contents aren't printed as wanted . But the other contents are printed as wanted . I know there might have been any problem in dynamic memory allocation of mine . But I can't understand . Any help would be appreciated .
Thanks ...
EXPECTED OUTPUT
Output for the containerArray1 object :
0-th element of 1st container array:
Calling copy constructor of Container
_____________________________________
The object has no elements
_____________________
Destructing Container
1-th element of 1st container array:
Calling copy constructor of Container
_____________________________________
There is an integer array in the container object
The values stored in the array are:
10 20 30
Freeing allocated memory for integer array
_____________________
Destructing Container
2-th element of 1st container array:
Calling copy constructor of Container
_____________________________________
There is only an integer value in the container object
The value is: 100
Freeing allocated memory for a single integer
_____________________
Destructing Container
Output for containerArray2 object :
0-th element of 2nd container array:
Calling copy constructor of Container
_____________________________________
There is an integer array in the container object
The values stored in the array are:
10 20 30
Freeing allocated memory for integer array
_____________________
Destructing Container
1-th element of 2nd container array:
Calling copy constructor of Container
_____________________________________
There is an integer matrix in the container object
The values stored in the matrix are:
1 2 3
4 5 6
Freeing allocated memory for integer matrix
_____________________
Destructing Container
The problem lies in the 0th element of the 2nd container object . The array prints abrupt numbers .
Your copy-constructor does not copy the values but just bends the pointers.
You allocated the memory but then you overwrite the pointer to the allocated memory.
So instead of this
value=new int;
value=obj.value;
valueArray=new int[firstDim];
valueArray=obj.valueArray;
valueMatrix=new int*[firstDim];
for(int k=0;k<obj.firstDim;k++){
valueMatrix[k]=new int[secondDim];
}
valueMatrix=obj.valueMatrix;
You need to do something like this:
value = nullptr;
valueArray = nullptr;
valueMatrix = nullptr;
storedType = obj.storedType;
switch (storedType)
{
case INTEGER:
value = new int;
*value = *(obj.value);
break;
case INT_ARRAY:
valueArray = new int[firstDim];
std::copy(obj.valueArray, obj.valueArray + firstDim, valueArray);
break;
case INT_MATRIX:
valueMatrix = new int* [firstDim];
for (int k = 0; k < obj.firstDim; k++) {
valueMatrix[k] = new int[secondDim];
std::copy(obj.valueMatrix[k], obj.valueMatrix[k] + secondDim, valueMatrix[k]);
}
break;
}
Since you are just dealing with int values you can just use memcpy instead std::copy, but I just thought I'd mention the general case.

Set array dimension at runtime

I have a struct, which, depending on user inputs at runtime, will either require a 1D array or a 3D array. It will never need both. Right now, I have it set up like in the sample code below, with separate variables that can point to either a 1D array, or a 3D array. I would like to have just one variable in the struct that can point to either a 1D array or a 3D array, where the dimension is set at runtime. I have intermediate knowledge of C, and am a beginner with C++. I'd be willing to accept an answer based on C++ concepts but only if there is no slowdown (or negligible slowdown) compared to using C when iterating over the values. If it's a 3D array, then the for loops that access and change the array's values are the biggest bottleneck in my code. Once the array is set up, I won't need to change the dimension or size of the array.
Is there a way to do this, or should I just settle for always having an extraneous variable in my struct?
#include <iostream>
using namespace std;
typedef struct {
int dim;
int *one_d_arr;
int ***three_d_arr;
} Struct;
int main() {
int count = 0;
int *arr1 = (int*) malloc(2 * sizeof(int));
arr1[0] = 0;
arr1[1] = 1;
int ***arr3 = (int***) malloc(2 * sizeof(int**));
for (int i=0; i<2; i++) {
arr3[i] = (int**) malloc(2 * sizeof(int*));
for (int j=0; j<2; j++) {
arr3[i][j] = (int*) malloc(2 * sizeof(int));
for (int k=0; k<2; k++) {
arr3[i][j][k] = count++;
}
}
}
Struct s;
s.one_d_arr = NULL;
s.three_d_arr = NULL;
cout << "Enter number of dimensions: ";
cin >> s.dim;
if (s.dim==1) {
s.one_d_arr = arr1;
cout << s.one_d_arr[0] << ", " << s.one_d_arr[1] << endl;
}
else if (s.dim==3) {
s.three_d_arr = arr3;
cout << s.three_d_arr[0][0][0] << ", " << s.three_d_arr[0][0][1] << endl;
cout << s.three_d_arr[0][1][0] << ", " << s.three_d_arr[0][1][1] << endl;
cout << s.three_d_arr[1][0][0] << ", " << s.three_d_arr[1][0][1] << endl;
cout << s.three_d_arr[1][1][0] << ", " << s.three_d_arr[1][1][1] << endl;
}
else {
cout << "Must enter 1 or 3" << endl;
}
}
My recommendation is to use two different types here, instead of a single struct. Using an abstract base class, you can make both subclasses conform to a single interface, but they would have different underlying behavior. A very basic example:
class ArrayBase {
int dim;
public:
// This function is pure virtual, which means it's impossible to
// instantiate an instance of ArrayBase. Any class that inherits from
// ArrayBase must implement printArray().
virtual void printArray() = 0;
}
class Array1D : public ArrayBase {
int* array;
void printArray() {
// some code to print this one-dimensional array
}
}
class Array3D : public ArrayBase {
int*** array;
void printArray() {
// some code to print this three-dimensional array
}
}
Later, when you need to use the array, you can dynamically allocate the type you need, like this:
ArrayBase* inputArray;
// if the user wants a 1D array
inputArray = new Array1D();
// if the user wants a 3D array
inputArray = new Array3D();
// this will call the appropriate function to print the array
inputArray->printArray();
If you really want to have a single type, using boost::any is one way to condense your two array pointers into one. I would not recommend this approach, but it would work.
One of the juicy things about the C/C++ pointers is the existence of void pointers. A void pointer can point to anything you want, from int to int ***.
So you can simply use the following code:
#define CAST1(arr) ((int *)arr)
#define CAST3(arr) ((int ***)arr)
#define CAST(arr,i) CAST##i(arr)
typedef struct {
int dim;
void *arr;
} Struct;
int main()
{
Struct s;
cin >> s.dim;
int count = 0;
if (s.dim == 1){
s.arr = malloc(2 * sizeof(int));
CAST(s.arr, 1)[0] = 0;
CAST(s.arr, 1)[1] = 1;
}
else if (s.dim == 3){
s.arr = malloc(2 * sizeof(int ***));
for (int i = 0; i < 2; i++){
CAST(s.arr, 3)[i] = (int **) malloc(2 * sizeof(int **));
for (int j = 0; j < 2; j++){
CAST(s.arr, 3)[i][j] = (int *)malloc(2 * sizeof(int *));
for (int k = 0; k < 2; k++){
CAST(s.arr, 3)[i][j][k] = count++;
}
}
}
}
if (s.dim == 1) {
cout << CAST(s.arr, 1)[0] << ", " << CAST(s.arr, 1)[1] << endl;
}
else if (s.dim == 3) {
cout << CAST(s.arr, 3)[0][0][0] << ", " << CAST(s.arr, 3)[0][0][1] << endl;
cout << CAST(s.arr, 3)[0][1][0] << ", " << CAST(s.arr, 3)[0][1][1] << endl;
cout << CAST(s.arr, 3)[1][0][0] << ", " << CAST(s.arr, 3)[1][0][1] << endl;
cout << CAST(s.arr, 3)[1][1][0] << ", " << CAST(s.arr, 3)[1][1][1] << endl;
}
else {
cout << "Must enter 1 or 3" << endl;
}
system("pause");
return 0;
}

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".

how to use exceptions and pointers in a vector class

I have this vector class, and I was provided with a driver to test the class. Most of it seems to work fine but I think there is something wrong with the exceptions part (which I haven't quite fully understood)
Here is the code for the class .cpp file
int myVector::at(int i)
{
if(i<vsize)
return array[i];
throw 10;
}
and here is the driver code
#include "myVector.h"
#include <iostream>
using namespace std;
int main()
{
// Create a default vector (cap = 2)
myVector sam;
// push some data into sam
cout << "\nPushing three values into sam";
sam.push_back(21);
sam.push_back(31);
sam.push_back(41);
cout << "\nThe values in sam are: ";
// test for out of bounds condition here
for (int i = 0; i < sam.size( ) + 1; i++)
{
try
{
cout << sam.at(i) << " ";
}
catch(int badIndex)
{
cout << "\nOut of bounds at index " << badIndex << endl;
}
}
cout << "\n--------------\n";
// clear sam and display its size and capacity
sam.clear( );
cout << "\nsam has been cleared.";
cout << "\nSam's size is now " << sam.size( );
cout << "\nSam's capacity is now " << sam.capacity( ) << endl;
cout << "---------------\n";
// Push 12 values into the vector - it should grow
cout << "\nPush 12 values into sam.";
for (int i = 0; i < 12; i++)
sam.push_back(i);
cout << "\nSam's size is now " << sam.size( );
cout << "\nSam's capcacity is now " << sam.capacity( ) << endl;
cout << "---------------\n";
cout << "\nTest to see if contents are correct...";
// display the values in the vector
for (int i = 0; i < sam.size( ); i++)
{
cout << sam.at(i) << " ";
}
cout << "\n--------------\n";
cout << "\n\nTest Complete...";
cout << endl;
system("PAUSE");
return 0;
}
Any help is appreciated. Thanks
The driver that you have provided:
try {
cout << sam.at(i) << " ";
}
catch(int badIndex) {
cout << "\nOut of bounds at index " << badIndex << endl;
}
expects that int will be thrown (a bit weird design, but well... this is the code that will use your class...). Your implementation of at() might look like this:
int& myVector::at(int i) throw(int) {
if (i < vsize)
return array[i];
throw i;
}
just try to follow one simple rule: throw by value, catch by reference.
Also note that you have a pointer:
private:
int* array;
which points to dynamically allocated memory allocated in constructor and copy constructor and freed in destructor :
myVector::myVector(int i)
{
...
array = new int[maxsize];
}
myVector::myVector(const myVector& v)//copy constructor
{
...
array =new int[maxsize];
}
myVector::~myVector()
{
delete[] array;
}
But how about the assignment operator ? See What is The Rule of Three?
Your stop condition of for loop ends it one element after the last one (i.e. you cannot access 4th element of sam vector because there are only three elements).
std::vector::at throws std::out_of_range exception in such situation (see: http://en.cppreference.com/w/cpp/container/vector/at), not int one. So you should change your exception handling part to something like this:
#include <exception>
try
{
cout << sam.at(i) << " ";
}
catch(std::out_of_range exc)
{
cout << "\nOut of bounds at index " << exc.what() << endl;
}

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 .