954,500 Members — Technology Publication meets Social Media
Username:
Password:
Lost login information?
Have something to say? Contribute New Article Reply to this Article

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.

Radical Edward
Posting Pro
545 posts since May 2008
Reputation Points: 361
Solved Threads: 97
 

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

Radical Edward
Posting Pro
545 posts since May 2008
Reputation Points: 361
Solved Threads: 97
 

> 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; }
Radical Edward
Posting Pro
545 posts since May 2008
Reputation Points: 361
Solved Threads: 97
 

> 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
 

> Anything I did wrong?
You forgot to take the index shift into account. The matrix class supports N-based arrays, but the internal memory is still 0-based. You should subtract the low end of the range from each index:

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+2)+55)" << endl;
*(*(arr2+2)+55) = 1234;
int test = *(*(arr2+2)+55);
cout << test <<'\n';
Radical Edward
Posting Pro
545 posts since May 2008
Reputation Points: 361
Solved Threads: 97
 

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.

Radical Edward
Posting Pro
545 posts since May 2008
Reputation Points: 361
Solved Threads: 97
 

> 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
 

> When you mean "safe way", there is a way but it would be dangerous to put in it?
Sure, you can subtract the pointer itself from within SA's operator* and that will shift the range before your arithmetic gets to it:

operator T*() { return p - low; }

Technically, it's not safe even to calculate the address of a pointer outside of the allocated memory, so the above code falls into the realm of Bad Codeā„¢.

Radical Edward
Posting Pro
545 posts since May 2008
Reputation Points: 361
Solved Threads: 97
 

This question has already been solved

Post: Markdown Syntax: Formatting Help
You