Safe Array within a Safe Array Implementation
Hello,
I have a project that needs to implement a Safe Array which is an Array that has bounds checking. On top of that I need to create a "Matrix" class which implements 2D which is basically a Safe array within a Safe array. This is also templatized.
The problem is it compiles fine with my eclipse but when I try to compile
in Unix it gives me this error: *** glibc detected *** double free or corruption: 0x0937d008 ***
Can someone check my code to see if there is anything wrong with it?
Also: Does anyone know why when it calls my copy constructor when making the 2D Safe Array? I have to comment it out inorder for it to work.
Here is my code:
#include <iostream>
#include <stdlib.h>
#include <assert.h>
using namespace std;
template <class T>
class SA{
private:
int low, high;
T* p;
public:
// default constructor
SA(){
low = 0;
high = -1;
p = NULL;
}//constructor
// 2 parameter constructor SA x(10,20);
SA(int l, int h){
if( (h - l + 1) <= 0 ){
cout << "constructor error in bounds definition" << endl;
exit(1);
}//if
low = l;
high = h;
p = new T[h-l+1];
}//2 parameter constructor
// single parameter constructor
// SA x(10); and getting an array x indexed from 0 to 9
SA(int i){
low = 0;
high = i - 1;
p = new T[i];
}//singple parameter constructor
/*
// copy constructor for pass by value and initialization
SA(const SA & s){
int size = s.high - s.low + 1;
p = new T[size];
for(int i=0; i<size; i++)
p[i] = s.p[i];
low = s.low;
high = s.high;
}//copy constructor
*/
// destructor
~SA(){
delete [] p;
}//destructor
//overloaded [] lets us write
//SA x(10,20); x[15]= 100;
T& operator[](int i){
if(i < low || i > high){
cout << "index "<< i << " out of range" << endl;
exit(1);
}//if
return p[i-low];
}//overloaded [] operator
// overloaded assignment lets us assign one SA to another
SA & operator=(const SA s){
if(this == &s)
return *this;
delete [] p;
int size = s.high - s.low + 1;
p = new T[size];
for(int i = 0; i < size; i++)
p[i] = s.p[i];
low = s.low;
high = s.high;
return *this;
}//overloaded = operator
// overloads << so we can directly print SAs
friend ostream& operator<<(ostream& os, SA s){
int size = s.high - s.low + 1;
for(int i = 0; i < size; i++)
cout << s.p[i] << endl;
return os;
};
};//class SafeArray
//Matrix class
template <class T>
class Matrix{
private:
SA < SA<T> > mat;
public:
//2 parameter constructor
Matrix(int row, int col){
mat = SA< SA<T> >(0, row-1);
for(int i = 0; i < row; i++){
mat[i] = SA<T>(0, col-1);
}//for
}//construct for 2 parameters
//4 parameter constructor
Matrix(int r1, int r2, int c1, int c2){
mat = SA< SA<T> >(r1, r2-1);
for(int i = r1; i < r2; i++)
mat[i] = SA<T>(c1, c2-1);
}//4 parameter constructor
SA<T> operator[](int r){
return(mat[r]);
}//operator[] overload
};//class Matrix
int main(){
Matrix <int>arr(5,10);//create 2D array of 5 rows and 10 cols
Matrix <int>arr2(10,20,100,200);//create 2D array of 10 rows from 10-19 and 100 cols from 100-199
arr[3][8]=1234;//test
cout << arr[3][8] << endl;
arr2[12][155]=1111;//test
cout << arr2[12][155] << endl;
//testing out of bounds
arr[5][6]=1;
int i = arr2[22][200];
return 0;
}//main
ff4930
Junior Poster in Training
58 posts since Oct 2007
Reputation Points: 34
Solved Threads: 3
> double free or corruption: 0x0937d008
With the copy constructor commented out, you have tons of alias pointers floating around. The destructor assumes that a copy constructor exists and allocates a unique pointer, but it doesn't.
> Can someone check my code to see if there is anything wrong with it?
You pass by value when you should be passing by reference. Basically anywhere SA is passed or returned, it should be either a reference or a const reference.
Hi Thanks for replying!
But when I uncomment the copy constructor, it doesn't seem to work when I do
Matrix arr(5,10);
arr[3][8]=1234;
because it calls the copy constructor.
Is there a way to fix this?
and thanks for telling to replace passing for value for reference, will make the changes.
ff4930
Junior Poster in Training
58 posts since Oct 2007
Reputation Points: 34
Solved Threads: 3
> Is there a way to fix this?
Sure, read the rest of Edward's reply and fix the pass-by-value problems. :D This in particular:
SA<T> operator[](int r){
The copy constructor is always called to create a new object for the return value of operator[] in your matrix class.
Wow, awsome! Thanks, you taught me something. If I don't pass by reference, the copy constructor will always be called because it is passed in by value and need a copy.
I have 1 more question:
We know that *(*(k+i)+j) is equivalent to k[i][j].
Is there a way to implement the same thing but with my matrix class?
Is there a pointer * overloading?
Can you point me or hint me on a way to accomplish this?
ff4930
Junior Poster in Training
58 posts since Oct 2007
Reputation Points: 34
Solved Threads: 3
> We know that *(*(k+i)+j) is equivalent to k[i][j].
> Is there a way to implement the same thing but with my matrix class?
Sure, but you have to do it by overloading all of the required operators. SA is a pointer under the hood so it's pretty easy by adding an implicit conversion operator to each class:
template <typename T>
SA<T>::operator T*() { return p; }
template <typename T>
Matrix<T>::operator SA<T>*() { return mat; }
Hmm, it seemed to compile fine but when I ran it, it gave me an error of "Segmentation fault"
I added your code.
added
operator SA<T>*() {return mat;}//operator * overload
in my matrix class
and added
operator T*(){return p;}//operator * overload
in my Safe Array class
Matrix <int>arr2(10,20,100,200);
//testing *(*(k+i)+j) is equivalent to k[i][j]
cout << "testing *(*(k+i)+j) is equivalent to k[i][j]" << endl;
cout << "testing arr2[12][155] which is *(*(arr2+12)+155)" << endl;
int test = *(*(arr2+12)+155);
cout << test;
Anything I did wrong?
ff4930
Junior Poster in Training
58 posts since Oct 2007
Reputation Points: 34
Solved Threads: 3
Im sorry, Im not too sure what you mean. Internal memory? and what you mean by the low end of the range?
Would I modify the code for the operator*?
ff4930
Junior Poster in Training
58 posts since Oct 2007
Reputation Points: 34
Solved Threads: 3
> Im sorry, Im not too sure what you mean.
If you create an object, SA(10, 20), you can access index 15 even though there are only 10 elements. That's because the SA class forces the index back into what it should be behind the scenes:
return p[i-low];
The operator* that Edward showed you doesn't include any of that adjustment logic so you have to use the correct indexes from the start. I can't think of a safe way to let you use the "fake" range without a lot of extra code.
> Would I modify the code for the operator*?
No, you would use the [] operator and avoid accessing the SA class' internal pointer.
Oh, I get what you mean. It works if I create without an offset such as SA(5,5).
When you mean "safe way", there is a way but it would be dangerous to put in it?
But Thanks so much for helping me this far.
I still have part 2 of this project to finish and if I come across any more troubles Ill post again. Thanks!!
ff4930
Junior Poster in Training
58 posts since Oct 2007
Reputation Points: 34
Solved Threads: 3