Thread: Dynamic Memory Problem

  1. #1
    Registered User
    Join Date
    Sep 2010
    Location
    Boston, MA
    Posts
    97

    Dynamic Memory Problem

    Alright so I have a class of Matrix which looks like
    Code:
    class Matrix
    {
    private:
    	string _name;
    	int errorInput;
    	int  _row;
    	int  _col;
    	double ** _mat;
    public:
    	//Constructors
    	Matrix();
    	Matrix(const Matrix &m);
    	//Deconstructor
    	~Matrix();
    	//swap for copy
    	void swap(Matrix& m);
    	//get functions for variables
    	string getName(void);
    	int getRow(void);
    	int getCol(void);
    	int getError(void);
    	//set functions for variables
    	void setName(string name);
    	//clear the matrix
    	void clear(void);
    	//transpose Matrix
    	Matrix transpose(void);
    	//operators to overload
    	Matrix & Matrix::operator = (const Matrix & mMatrix);
    	friend std::istream& operator>>(std::istream &is, Matrix & mMatrix);
    	friend ostream& operator<<(ostream& os, const Matrix& dt);
    	const Matrix operator+(double adder) const;
    	const Matrix operator-(double subber) const;
    	const Matrix operator*(double multer) const;
    	const Matrix operator+(const Matrix &rhs) const;
    	const Matrix operator-(const Matrix &rhs) const;
    	const Matrix operator*(const Matrix &rhs) const;
    And whenever an instances destructor gets called I face heap errors such as

    In non-debugging mode i get this
    Code:
    HEAP CORRUPTION DETECTED: after normal block (#184) at 0x004E95A8.
    CRT Detected that the application wrote to memory after the end of heap buffer
    This in debug mode. Says windows has triggered a break point and brings me to the function below.

    Code:
    /***
    *int _CrtIsValidHeapPointer() - verify pointer is from 'local' heap
    *
    *Purpose:
    *       Verify pointer is not only a valid pointer but also that it is from
    *       the 'local' heap. Pointers from another copy of the C runtime (even in the
    *       same process) will be caught.
    *
    *Entry:
    *       const void * pUserData     - pointer of interest
    *
    *Return:
    *       TRUE - if valid and from local heap
    *       FALSE otherwise
    *
    *******************************************************************************/
    extern "C" _CRTIMP int __cdecl _CrtIsValidHeapPointer(
            const void * pUserData
            )
    {
            if (!pUserData)
                return FALSE;
    
            if (!_CrtIsValidPointer(pHdr(pUserData), sizeof(_CrtMemBlockHeader), FALSE))
                return FALSE;
    
            return HeapValidate( _crtheap, 0, pHdr(pUserData) );
    }.
    Now I have done as much investigating possible, in the matter of the address that gets deleted.

    Basically a flow chart of what happens is the following

    Code:
    I call the clear function of a temp instance a matrix.
    -> then in the clear function I use a copy and swap type of clear where I create
     a new temp instance of matrix and swap that with with the current matrix's contents 
    which then when leaves calls the destructor of the temp instance which now holds 
    the old data.
    
    -> in the destructor i go row by row and delete the pointer of each row and
     then delete the head pointer. When i try to delete a row i get the errors.
    My destructor looks like

    Code:
    Matrix::~Matrix()
    {
    	for(int i = 0; i < _row; i++)
    	{
    		delete[] _mat[i];
    	}
    	delete[] _mat;
            _mat = NULL;
    }
    And my copy constructor looks like

    Code:
    Matrix::Matrix(const Matrix &m)
    {
    	int i,j;
    	_row = m._row;
    	_col = m._col;
    	_name = m._name;
    	errorInput = m.errorInput;
    	_mat = new double *[_row];
    	for(i=0;i<_row;i++)
    	{
    		_mat[i] = new double [_col];
    		for(j=0;j<_col;j++)
    		{
    			_mat[i][j] = m._mat[i][j];
    		}
    	}
    }
    I have my destructor print out addresses before deleting them and they all check out to the data I want to get deleted. But for some reason I get those two errors. Thoughts?
    Last edited by omGeeK; 04-15-2012 at 06:41 PM.

  2. #2
    - - - - - - - - oogabooga's Avatar
    Join Date
    Jan 2008
    Posts
    2,808
    Show your clear and operator= functions.
    The cost of software maintenance increases with the square of the programmer's creativity. - Robert D. Bliss

  3. #3
    Registered User
    Join Date
    Sep 2010
    Location
    Boston, MA
    Posts
    97
    clear
    Code:
    void Matrix::clear(void) 
    {     
    	Matrix temp;     
    	swap(temp); 
    }
    Assignment operator
    Code:
    Matrix & Matrix::operator = (const Matrix& mMatrix)
    {
    	Matrix temp(mMatrix);
    	swap(temp);
    
    	return *this;
    }
    swap
    Code:
    void Matrix::swap(Matrix& m) 
    {
    	//uses std::swap and swaps the current matrix's contents with the contents of the arg m  - 1 by 1     
    	std::swap(_name, m._name);     
    	std::swap(_row, m._row); 
    	std::swap(_col, m._col);
    	std::swap(errorInput, m.errorInput);
    	std::swap(_mat,m._mat);
    }
    Last edited by omGeeK; 04-15-2012 at 06:41 PM.

  4. #4
    Registered User
    Join Date
    Sep 2010
    Location
    Boston, MA
    Posts
    97
    The thing that is confusing me is that the right memory I want to delete is actually in the destructor. So I have no clue why delete[] won't work on it. Some more background info, is that I try clearing the temp instance after I push it into a vector for my list. Maybe that is a problem? But doesn't pushing it into a vector re dynamically allocate it in the list because thats the way std::vector's are set up.

  5. #5
    - - - - - - - - oogabooga's Avatar
    Join Date
    Jan 2008
    Posts
    2,808
    Can't see anything yet. Can you post all the code? A runnable program?
    The cost of software maintenance increases with the square of the programmer's creativity. - Robert D. Bliss

  6. #6
    Registered User
    Join Date
    Sep 2010
    Location
    Boston, MA
    Posts
    97
    Alright well the code is pretty long so cheers lol. But the program will not run in release mode at all. But when I comment out the destructors code, it works fine in debug mode with no debugging.
    Code:
    #include "Matrix.h"
    
    //default constructor
    Matrix::Matrix()
    {
    	_name = "";
    	_row = 0;
    	_col = 0;
    	_mat = NULL;
    	errorInput = 1;
    }
    //copy constructor call
    Matrix::Matrix(const Matrix &m)
    {
    	int i,j;
    	_row = m._row;
    	_col = m._col;
    	_name = m._name;
    	errorInput = m.errorInput;
    	_mat = new double *[_row];
    	for(i=0;i<_row;i++)
    	{
    		_mat[i] = new double [_col];
    		for(j=0;j<_col;j++)
    		{
    			_mat[i][j] = m._mat[i][j];
    		}
    	}
    }
    //destructor
    Matrix::~Matrix()
    {
    	for(int i = 0; i < _row; i++)
    	{
    		delete[] _mat[i];
    	}
    	delete[] _mat;
    	_mat = NULL;
    }
    //swap for the copy
    void Matrix::swap(Matrix& m) 
    {
    	//uses std::swap and swaps the current matrix's contents with the contents of the arg m  - 1 by 1     
    	std::swap(_name, m._name);     
    	std::swap(_row, m._row); 
    	std::swap(_col, m._col);
    	std::swap(errorInput, m.errorInput);
    	std::swap(_mat,m._mat);
    }
    //returns the name of a matrix
    string Matrix::getName(void)
    {
    	return _name;
    }
    //returns the number of rows
    int Matrix::getRow(void)
    {
    	return _row;
    }
    //returns the number of columns
    int Matrix::getCol(void)
    {
    	return _col;
    }
    //returns the error 
    int Matrix::getError(void)
    {
    	return errorInput;
    }
    //clear the matrix by using the copy swap idiom and creating a blank temp and swapping it with the
    //current matrixs data. then when exits destructor gets called to destroy temp (old data)
    void Matrix::clear(void) 
    {     
    	Matrix temp;     
    	swap(temp); 
    } 
    //this sets the name of the string passed to matrixs name
    void Matrix::setName(string name)
    {
    	_name.clear();
    	_name = name;
    }
    //transpose a matrix uses the copy and swap idiom again by using a copy constructor to create a temp instance
    //with the data of the current matrix and a default constructor for another.  Set the corresponding rows and columns 
    //by reversing the order from the current matrix. while using the same new double method and swapping at the end with the new data
    Matrix Matrix::transpose(void)
    {
    	Matrix temp1;
    	temp1._row = _col;
    	temp1._col = _row;
    	temp1._mat = new double *[temp1._row];
    	for(int i = 0; i < temp1._row; i++)
    	{
    		temp1._mat[i] = new double [temp1._col];
    		for(int j = 0; j < temp1._col; j++)
    		{
    			temp1._mat[i][j] = _mat[j][i];
    		}
    	}
    	return temp1;
    }
    //sets the data of a matrix given a matrix operator overloading
    //assignment operator just another copy and swap
    Matrix & Matrix::operator = (const Matrix& mMatrix)
    {
    	Matrix temp(mMatrix);
    	swap(temp);
    
    	return *this;
    }
    //overloaded input stream operator
    std::istream& operator>>(std::istream &is, Matrix & mMatrix)
    {
    	string tempString,restOfLine;
    	istringstream tempNumString;
    	deque<string> sList;
    	int row = 0;
    	int col = 0;
    	int foundEnd = 0;
    	int lastCol = 0;
    	double tempDBL;
    	//set flags for ios
    	std::ios_base::fmtflags temp=is.flags();
    	//get the entire line of input
    	getline(cin,restOfLine);
    	for(string::iterator sIT = restOfLine.begin(); sIT != restOfLine.end(); ++sIT)
    	{
    		//should only be one [ and it should be at the beginning
    		if(*sIT == '[')
    		{
    			//error if the [ is not at the begining of the line and thats it
    			if(sIT != restOfLine.begin())
    			{
    				mMatrix.errorInput = 3;
    				return is;
    			}
    		}
    		//the character is an ] then this is the final go around
    		else if(*sIT == ']')
    		{
    			if(tempString.size() > 0)
    			{
    				sList.push_back(tempString);
    				tempString.clear();
    				col++;
    				//check col
    				if(lastCol == 0)
    				{
    					lastCol = col;
    					row++;
    				}
    				else if(lastCol == col)
    				{
    					row++;
    				}
    				else
    				{
    					mMatrix.errorInput = 2;
    					return is;
    				}
    			}
    			else
    			{
    				//check col
    				if(lastCol == 0)
    				{
    					lastCol = col;
    					row++;
    				}
    				else if(lastCol == col)
    				{
    					row++;
    				}
    				else
    				{
    					mMatrix.errorInput = 2;
    					return is;
    				}
    			}
    			foundEnd = 1;
    		}
    		else if(*sIT == ';')
    		{
    			if(tempString.size() > 0)
    			{
    				sList.push_back(tempString);
    				tempString.clear();
    				col++;
    				//check col
    				if(lastCol == 0)
    				{
    					lastCol = col;
    					row++;
    					col = 0;
    				}
    				else if(lastCol == col)
    				{
    					row++;
    					col = 0;
    				}
    				else
    				{
    					mMatrix.errorInput = 2;
    					return is;
    				}
    			}
    			else
    			{
    				//check col
    				if(lastCol == 0)
    				{
    					lastCol = col;
    					row++;
    					col = 0;
    				}
    				else if(lastCol == col)
    				{
    					row++;
    					col = 0;
    				}
    				else
    				{
    					mMatrix.errorInput = 2;
    					return is;
    				}
    			}
    		}
    		//if find whitespace then gotta do a new column case if there is something in tempString
    		else if(*sIT == ' ')
    		{
    			if(tempString.size() > 0)
    			{
    				sList.push_back(tempString);
    				tempString.clear();
    				col++;
    			}
    			else
    			{
    				//then junk or just did above so skip over everything
    			}
    		}
    		//then the chacter must be something other than  '['	']'		';'		' '
    		else
    		{
    			//if it is a valid number then push it into a string
    			if(*sIT > 47 && *sIT < 58)
    			{
    				tempString.push_back(*sIT);
    			}
    			//if its not a valid number then leave 
    			//and return proper error
    			else
    			{
    				mMatrix.errorInput = 3;
    				return is;
    			}
    		}
    	}
    	mMatrix.errorInput = 1;
    	mMatrix._row = row;
    	mMatrix._col = col;
    	//and do a final assignment to the matrix passed to the stream
    	mMatrix._mat = new double *[row-1];
    	for(int i=0;i<row;i++)
    	{
    		mMatrix._mat[i] = new double [col-1];
    		for(int j=0;j<col;j++)
    		{
    			//use isstringstreams to convert the string to a double
    			tempNumString.str(sList.front());
    			tempNumString >> tempDBL;
    			//then pop front to get the next string in line
    			sList.pop_front();
    			//clear the isstrinstream
    			tempNumString.clear();
    			//and finally assign the matrix its value
    			mMatrix._mat[i][j] = tempDBL;
    		}
    	}
    	is.flags(temp);
    	return is;
    }
    //overloaded operator for cout
    //just a simple display loop
    ostream& operator<<(ostream& os, const Matrix& m)
    {
    	std::ios_base::fmtflags temp=os.flags();
    	int i,j;
    	cout << m._name << " =" << endl << endl;
    	for(i=0;i<m._row;i++)
    	{
    		for(j=0;j<m._col;j++)
    		{
    			cout << "\t" << m._mat[i][j];
    		}
    		cout << endl;
    	}
    	cout << endl << endl;
    	os.flags(temp);
    	return os;
    }
    //simple scalar addition with a matrix
    const Matrix Matrix::operator+ (double adder)const
    {
    	Matrix result(*this);
    	for(int i = 0; i < _row; i++)
    	{
    		for(int j = 0; j < _col; j++)
    		{
    			result._mat[i][j] += adder;
    		}
    	}
    	return result;
    }
    //simple scalar subtraction with a matrix
    const Matrix Matrix::operator- (double subber)const
    {
    	Matrix result(*this);
    	for(int i = 0; i < _row; i++)
    	{
    		for(int j = 0; j < _col; j++)
    		{
    			result._mat[i][j] -= subber;
    		}
    	}
    	return result;
    }
    //simple scalar multiplication with a matrix
    const Matrix Matrix::operator* (double multer)const 
    {
    	Matrix result(*this);
    	for(int i = 0; i < _row; i++)
    	{
    		for(int j = 0; j < _col; j++)
    		{
    			result._mat[i][j] *= multer;
    		}
    	}
    	return result;
    }
    //addition between two matrices the rows and columns of each must equal 
    //then add term by term
    const Matrix Matrix::operator+(const Matrix &rhs) const
    {
    	Matrix result(*this);
    	if(_row == rhs._row && _col == rhs._col)
    	{
    		for(int i = 0; i< _row; i++)
    		{
    			for(int j = 0 ; j<_col ; j++)
    			{
    				result._mat[i][j] += rhs._mat[i][j];
    			}
    		}
    	}
    	return result;
    }
    //subtraction between two matrices the rows and columns of each must equal 
    //then subtract term by term
    const Matrix Matrix::operator-(const Matrix &rhs) const
    {
    	Matrix result(*this);
    	if(_row == rhs._row && _col == rhs._col)
    	{
    		for(int i = 0; i< _row; i++)
    		{
    			for(int j = 0 ; j<_col ; j++)
    			{
    				result._mat[i][j] -= rhs._mat[i][j];
    			}
    		}
    	}
    	return result;
    }
    //multiplactions between two matrices the new size of the matrix 
    //will be the rows of the first matrix by the columns of the second matrix
    //and do the special math for each term (result._mat[i][j] = result._mat[i][j] + _mat[i][k] * rhs._mat[k][j])
    const Matrix Matrix::operator*(const Matrix &rhs) const
    {
    	Matrix result;
    	result._mat = new double*[_row];
    	for(int i=0;i<_row;i++)
    	{
    		result._mat[i] = new double [rhs._col];
    		for(int j=0;j<rhs._col;j++)
    		{
    			result._mat[i][j] = 0;
    			for(int k=0;k< _col;k++)
    			{
    				result._mat[i][j] = result._mat[i][j] + _mat[i][k] * rhs._mat[k][j];
    			}
    		}
    	}
    	//then set the new rows to the final matrix along with the cols
    	//and its errorinput to a 1
    	result._row = _row;
    	result._col = rhs._col;
    	result.errorInput = 1;
    	return result;
    }
    main.cpp

    Code:
    #include "Matrix.h"
    /* THE FOLLOWING TWO FUNCTIONS MUST BE COMPLETED; THEY ARE LISTED AT THE BOTTOM OF THIS FILE */
    // Finds matrix with name n in vector mL; returns -1 if matrix is not present
    int findMatrix(vector <Matrix> &mL, string n);
    // Adds matrix m to vector mL; returns position where added
    int addMatrix(vector <Matrix> &mL, Matrix &m);
    
    int main() 
    {
    	//definitions
    	vector <Matrix> mList;					// List of variables in program
    	string cmd, cmd2, cmd3;					// Strings for command input
    	string restOfLine, tempString;			// Used to clear input stream on errors
    	char c;									// Holds single input character
    	Matrix temp;							// Temporary matrix object
    	int pos, pos2, pos3;					// Used to hold position of matrices in mList
    	char op;								// Operator
    	int scalar;								// Scalar input variable
    
    	//forever while loop
    	while (1) 
    	{
    		//display indicator
    		//and scan in the first thing should be a name of a matrix or cmd of exit clear who or whos
    		cout << ">> ";
    		cin >> cmd;
    
    		if (cmd == "exit")				// Exit program
    			return 0;
    
    		else if (cmd == "clear")		// Clear all variables
    			mList.clear();
    
    		else if (cmd == "who") 
    		{		
    			if(mList.size() > 0)
    			{
    				// Print variable names
    				cout << "Your variables are:" << endl << endl;
    				for(vector<Matrix>::iterator iT = mList.begin(); iT != mList.end(); ++iT)
    				{
    					cout << iT->getName() << "\t";
    				}
    				cout << endl << endl;
    			}
    		}
    		else if (cmd == "whos") 
    		{	
    			if(mList.size() > 0)
    			{
    				// Print detailed variable information
    				cout << "Name\tSize\tBytes" << endl << endl;
    				for(vector<Matrix>::iterator iT = mList.begin(); iT != mList.end(); ++iT)
    				{
    					cout << iT->getName() << "\t" << iT->getRow() << "x" << iT->getCol() << "\t" << (int)iT->getRow() * (int)iT->getCol() * 8 << " bytes" << endl << endl;
    				}
    			}
    		}
    
    		/* If no conditions above are true, treat cmd as name of matrix
    		* Possible commands include:
    		*  M = [<list>]	Create new matrix
    		*  M = M			Assign one matrix to another
    		*  M = M'			Assign the transpose of one matrix to another
    		*  M = -M			Assign the negative of one matrix to another
    		*  M = M op M		Perform op (+, -, *) on two matrices and assign result to matrix
    		*  M = M op S		Perform op (+, -, *) on matrix and scalar and assign result to matrix */
    		else 
    		{
    
    			// cmd should be treated as matrix name--see if it's in mList
    			// Will use value of pos later
    			pos = findMatrix(mList, cmd);
    			//if following the name of matrix is a new line then print contents of the matrix
    			if (cin.peek() == '\n') 
    			{	
    				// End of line--should print contents of current matrix
    				// Matrix not found--print error
    				if (pos == -1)
    					cerr << "Error: undefined matrix " << cmd << endl;
    				// Matrix found--print it
    				else
    					cout << mList[pos];
    			}
    			//if not new line character then the next charcter must be an = by itself
    			else 
    			{
    				cin >> c;
    				if (c != '=') 
    				{		
    					// Wrong character--print error and clear input stream
    					cerr << "Error: incorrectly formatted command" << endl;
    					getline(cin, restOfLine);
    				}
    				else
    				{
    					/* How you handle the next part of the input depends on whether the 
    					* first character is '[' or not--if it is, you're creating a new 
    					* matrix (or assigning new values to an existing one); if it's not,
    					* then you're doing some sort of matrix operation. The >> operator
    					* will assume that you're reading in everything starting with the '[',
    					* so the code below will scan the input and discard all whitespace
    					* characters. You can't just use "cin >>" because you don't know
    					* what the next character will be. */
    
    					//skip the whitespace between the = and what follows
    					while ((c = cin.peek()) == ' ')
    						cin.get(c);
    
    					// Check for '[' --> assigning new values to matrix
    					if (c == '[') 
    					{
    						//if the matrix name is not found on the left of = then 
    						//must create the matrix parse the info from the [...] and use addMatrix to assign matrix
    						//to the list
    						if (pos == -1) 
    						{	
    							//clear all the leftover contents of temp
    							temp.clear();
    							//call the istream operator to parse what follows in the [...]
    							cin >> temp;
    							//upon return from the istream overloaded operator
    							//switch for errors
    							switch(temp.getError())
    							{
    								//if error is a 2 then the dimensions within the matrix are not the same
    							case 2:
    								temp.clear();
    								cout << "Dimensions don't match" << endl;
    								
    								break;
    								//if error is a 3 then the matrix is missing the ]
    							case 3:
    								temp.clear();
    								cout << "Improperly formatted matrix" << endl;
    								
    								break;
    								//if error is a 4 then the matrix has a character in it   [..a; 1 2 a]
    							case 4:
    								temp.clear();
    								cout << "Improperly formatted matrix" << endl;
    								
    								break;
    								//if none above then the no error and good to set the name of the matrix to that
    								//from cmd which holds the name left of =
    								//then add instance of matrix to list and display it
    							default:
    								temp.setName(cmd);
    								addMatrix(mList,temp);
    								cout << temp;
    								break;
    							}
    
    						}
    						else
    						{
    							//same as above except the name of matrix to left of = was found
    							//so only thing that changes is the default case which sets the matrix appropriate
    							//index in list to the temp instance
    							cin >> temp;
    							switch(temp.getError())
    							{
    							case 2:
    								temp.clear();
    								cout << "Dimensions don't match" << endl;
    								
    								break;
    							case 3:
    								temp.clear();
    								cout << "Improperly formatted matrix" << endl;
    								
    								break;
    							case 4:
    								temp.clear();
    								cout << "Improperly formatted matrix" << endl;
    								
    								break;
    							default:
    								temp.setName(cmd);
    								mList.erase(mList.begin() + pos);
    								addMatrix(mList,temp);
    								cout << temp;
    								break;
    							}
    						}
    					}
    
    					// Other commands of form M = expression
    					else 
    					{
    						cin >> cmd2;	// Read matrix name
    
    						/* End of line--command must be:
    						*  M = M			Assign one matrix to another
    						*  M = M'			Assign the transpose of one matrix to another
    						*  M = -M			Assign the negative of one matrix to another */
    						if (cin.peek() == '\n') 
    						{
    							// Transpose if find ' in the following string
    							if (cmd2.find('\'', cmd2.size() - 1) != string::npos) 
    							{
    								//get the name of matrix to traspose by itself
    								cmd2 = cmd2.substr(0, cmd2.size() - 1);
    								//find its index in list
    								pos2 = findMatrix(mList, cmd2);
    								//if matrix on right of = doesnt exist then return error
    								if (pos2 == -1)
    									cerr << "Error: undefined matrix " << cmd2 << endl;
    								else 
    								{
    									//if the matrix on right was found then 
    									//clear the temp instance and set it to the transposed
    									//matrix of the index from the list
    									temp.clear();
    									temp = mList[pos2].transpose();
    									//set the name of the matrix to the name on the left
    									temp.setName(cmd);
    									//if matrix on left is not found then add new matrix
    									if(findMatrix(mList,cmd) == -1)
    									{
    										addMatrix(mList,temp);
    										cout << temp;
    									}
    									//else set the index from list to the new temp instance
    									else
    									{
    										mList.erase(mList.begin() + pos);
    										addMatrix(mList,temp);	
    										cout << temp;
    									}
    								}
    							}
    
    							// Negative
    							else if (cmd2.find('-') == 0) 
    							{
    								//find the matrix name following the first character which should be the -
    								cmd2 = cmd2.substr(1);
    								pos2 = findMatrix(mList, cmd2);
    								//if the matrix does not exist then error otherwise 
    								//set the matrix on left of = to the - of the matrix on right
    								if (pos2 == -1)
    									cerr << "Error: undefined matrix " << cmd2 << endl;
    								else 
    								{
    									//if matrix on left is not found then add new matrix
    									//with the appropriate neg data
    									if(findMatrix(mList,cmd) == -1)
    									{
    										temp.clear();
    										temp = mList[pos2] * (-1);
    										temp.setName(cmd);
    										addMatrix(mList,temp);
    										cout << temp;
    									}
    									//else set the index from list to the right matrix * -1
    									else
    									{
    										temp = mList[pos2] * (-1);
    										temp.setName(cmd);
    										mList.erase(mList.begin() + pos);
    										addMatrix(mList,temp);	
    										cout << temp;
    									}
    								}
    							}
    							// Basic assignment
    							else 
    							{
    								pos2 = findMatrix(mList, cmd2);
    								//if the matrix on the right is not found 
    								//then return error otherwise set matrix on left to right
    								if (pos2 == -1)
    									cerr << "Error: undefined matrix " << cmd2 << endl;
    								else 
    								{
    									//if matrix on left is not found then add new matrix
    									//by clearing temp and then add matrix with the appropriate data
    									if(findMatrix(mList,cmd) == -1)
    									{
    										temp.clear();
    										temp = mList[pos2];
    										temp.setName(cmd);
    										addMatrix(mList,temp);
    										cout << temp;
    									}
    									//else set the index from list to the right matrix
    									else
    									{
    										temp = mList[pos2];
    										temp.setName(cmd);
    										mList.erase(mList.begin() + pos);
    										addMatrix(mList,temp);	
    										cout << temp;
    									}
    								}
    							}
    						}
    
    						/* Command must take one of two forms:
    						*  M = M op M		Perform op (+, -, *) on two matrices and assign result to matrix
    						*  M = M op S		Perform op (+, -, *) on matrix and scalar and assign result to matrix */ 
    						else
    						{
    							cin >> op;		// Read operator
    
    							/* Remove whitespace--need to be able to check if next string
    							is matrix or scalar */
    							while ((c = cin.peek()) == ' ')
    								cin.get(c);
    
    							// Scalar input--command is M op S
    							// Must fix name in each case when done
    							if ((c >= '0') && (c <= '9'))
    							{
    								//get the following number following the op
    								cin >> scalar;
    								//find if the matrix on the right of the = which has an op and scalar to it
    								//exists if it doesn return error if it does exist figure of what the op is and do according
    								pos2 = findMatrix(mList, cmd2);
    								if (pos2 == -1)
    									cerr << "Error: undefined matrix " << cmd2 << endl;
    								else
    								{
    									//switch for the op code
    									switch (op) 
    									{
    										//if the op is + then a simple scalar addition is required
    									case '+':
    										//if matrix on left is not found then add new matrix
    										//with the appropriate data from addition of scalar
    										if(findMatrix(mList,cmd) == -1)
    										{
    											temp.clear();
    											temp = mList[pos2] + scalar;
    											temp.setName(cmd);
    											addMatrix(mList,temp);
    											cout << temp;
    										}
    										//else set the index from list to the right matrix + scalar
    										else
    										{
    											temp.clear();
    											temp = mList[pos2] + scalar;
    											temp.setName(cmd);
    											mList.erase(mList.begin() + pos);
    											addMatrix(mList,temp);	
    											cout << temp;
    										}
    										break;
    										//simple subtraction of scalar and matrix
    									case '-':
    										//if matrix on left is not found then add new matrix
    										//with the appropriate data from subtraction of scalar
    										if(findMatrix(mList,cmd) == -1)
    										{
    											temp.clear();
    											temp = mList[pos2] - scalar;
    											temp.setName(cmd);
    											addMatrix(mList,temp);
    											cout << temp;
    										}
    										//else set the index from list to the right matrix - scalar
    										else
    										{
    											temp.clear();
    											temp = mList[pos2] - scalar;
    											temp.setName(cmd);
    											mList.erase(mList.begin() + pos);
    											addMatrix(mList,temp);	
    											cout << temp;
    										}
    										break;
    									case '*':
    										//if matrix on left is not found then add new matrix
    										//with the appropriate data multiplied by scalar
    										if(findMatrix(mList,cmd) == -1)
    										{
    											temp.clear();
    											temp = mList[pos2] * scalar;
    											temp.setName(cmd);
    											addMatrix(mList,temp);
    											cout << temp;
    										}
    										//else set the index from list to the right matrix * scalar
    										else
    										{
    											temp.clear();
    											temp = mList[pos2] * scalar;
    											temp.setName(cmd);
    											mList.erase(mList.begin() + pos);
    											addMatrix(mList,temp);	
    											cout << temp;
    										}
    										break;
    									default:
    										cerr << "Error: undefined operation " << op << endl;
    									}
    								}
    							}
    
    							// Matrix input--command is M op M
    							else {
    								cin >> cmd3;
    								//scanned in the 3rd matrix name time to check both matrices on right of = exist
    								//if matrix before op doesnt exit return error otherwise check other matrix
    								pos2 = findMatrix(mList, cmd2);
    								if (pos2 == -1)
    									cerr << "Error: undefined matrix " << cmd2 << endl;
    								else 
    								{
    									//if matrix on right of op doesnt exist then return error
    									//otherwise both exist time to do the math
    									pos3 = findMatrix(mList, cmd3);
    									if (pos3 == -1)
    										cerr << "Error: undefined matrix " << cmd3 << endl;
    									else 
    									{
    										//switch statement for the op between the two matrices
    										switch(op) 
    										{
    											//addition of the two matrices requires them to be the same exact size
    										case '+':
    											if(mList[pos2].getCol() == mList[pos3].getCol() && mList[pos2].getRow() == mList[pos3].getRow())
    											{
    												//if the matrices are the same size then do the apporpiate math for the matrix 
    												//on the left of the = and find out if it exists or not
    												if(findMatrix(mList,cmd) == -1)
    												{
    													temp.clear();
    													temp = mList[pos2] + mList[pos3];
    													temp.setName(cmd);
    													addMatrix(mList,temp);
    													cout << temp;
    												}
    												//else set the index from list to the right matrix + 2nd right matrix
    												else
    												{
    													temp.clear();
    													temp = mList[pos2] + mList[pos3];
    													temp.setName(cmd);
    													mList.erase(mList.begin() + pos);
    													addMatrix(mList,temp);	
    													cout << temp;
    												}
    											}
    											else
    												cout << "Error: dimensions are inconsistent" << endl;
    											break;
    										case '-':
    											if(mList[pos2].getCol() == mList[pos3].getCol() && mList[pos2].getRow() == mList[pos3].getRow())
    											{
    												//if the matrices are the same size then do the apporpiate math for the matrix 
    												//on the left of the = and find out if it exists or not
    												if(findMatrix(mList,cmd) == -1)
    												{
    													temp.clear();
    													temp = mList[pos2] - mList[pos3];
    													temp.setName(cmd);
    													addMatrix(mList,temp);
    													cout << temp;
    												}
    												//else set the index from list to the right matrix - 2nd right matrix
    												else
    												{
    													temp.clear();
    													temp = mList[pos2] - mList[pos3];
    													temp.setName(cmd);
    													mList.erase(mList.begin() + pos);
    													addMatrix(mList,temp);	
    													cout << temp;
    												}
    											}
    											else
    												cout << "Error: dimensions are inconsistent" << endl;
    											break;
    										case '*':
    											//for matrix multiplication then the columns of the first matrix
    											//must equal the rows of the second matrix
    											if(mList[pos2].getCol() == mList[pos3].getRow())
    											{
    												//if the matrices are the appropriate size for matrix multiplication
    												//then do the apporpiate math for the matrix on the left of the = and find out if it exists or not
    												if(findMatrix(mList,cmd) == -1)
    												{
    													temp.clear();
    													temp = mList[pos2] * mList[pos3];
    													temp.setName(cmd);
    													addMatrix(mList,temp);
    													cout << temp;
    												}
    												//else set the index from list to the right matrix * 2nd right matrix
    												else
    												{
    													temp.clear();
    													temp = mList[pos2] * mList[pos3];
    													temp.setName(cmd);
    													mList.erase(mList.begin() + pos);
    													addMatrix(mList,temp);	
    													cout << temp;
    												}
    											}
    											else
    												cout << "Error: inner dimensions must match" << endl;
    											break;
    										default:
    											cerr << "Error: undefined operation " << op << endl;
    										}
    									}
    								}
    							}
    						}
    					}
    				}
    			}
    		}
    	}
    }
    
    // Finds matrix with name n in vector mL; returns -1 if matrix not present
    int findMatrix(vector <Matrix> &mL, string n) 
    {
    	for(vector<Matrix>::iterator iT = mL.begin(); iT != mL.end(); ++iT)
    	{
    		//if strings match use std function called distance to find the number of elements between 
    		//the beginning of a vector and the current itereator pos
    		if(iT->getName() == n)
    			return (int)distance(mL.begin(), iT);
    	}
    	return -1;
    }
    
    // Add m to array of matrices
    int addMatrix(vector <Matrix> &mL, Matrix &m) 
    {
    	mL.push_back(m);
    	Matrix tmp, tmp1;
    	for(long i=0;i<mL.size();i++)
    	{
    		for(long x=0; x<mL.size()-1-i; x++)
    		{
    			if(mL[x].getName() > mL[x+1].getName())
    			{
    				//r.push_back(rnd);
    				tmp = mL[x];
    				mL[x] =  mL[x+1];
    				mL[x+1] = tmp;
    			}
    		}
    	}
    	return -1;
    }
    header

    Code:
    #pragma once
    #include <vector>
    #include <string>
    #include <sstream>
    #include <deque>
    #include <iostream>
    #include <iomanip>
    using namespace std;
    
    class Matrix
    {
    private:
    	string _name;
    	int errorInput;
    	int  _row;
    	int  _col;
    	double ** _mat;
    	deque<string> mSList;
    public:
    	//Constructors
    	Matrix();
    	Matrix(const Matrix &m);
    	//Deconstructor
    	~Matrix();
    	//swap for copy
    	void swap(Matrix& m);
    	//get functions for variables
    	string getName(void);
    	int getRow(void);
    	int getCol(void);
    	int getError(void);
    	//set functions for variables
    	void setName(string name);
    	//clear the matrix
    	void clear(void);
    	//transpose Matrix
    	Matrix transpose(void);
    	//operators to overload
    	Matrix & Matrix::operator = (const Matrix & mMatrix);
    	friend std::istream& operator>>(std::istream &is, Matrix & mMatrix);
    	friend ostream& operator<<(ostream& os, const Matrix& dt);
    	const Matrix operator+(double adder) const;
    	const Matrix operator-(double subber) const;
    	const Matrix operator*(double multer) const;
    	const Matrix operator+(const Matrix &rhs) const;
    	const Matrix operator-(const Matrix &rhs) const;
    	const Matrix operator*(const Matrix &rhs) const;
    };
    Last edited by omGeeK; 04-15-2012 at 07:35 PM.

  7. #7
    - - - - - - - - oogabooga's Avatar
    Join Date
    Jan 2008
    Posts
    2,808
    Ouch! Okay, I've got a copy of it running. You can delete the code above if you want to keep it secret. BTW, how do I enter a 2D matrix? I can enter
    a = [1 2 3 4]
    but not
    a = [[1 2 3] [4 5 6]]
    The cost of software maintenance increases with the square of the programmer's creativity. - Robert D. Bliss

  8. #8
    Registered User
    Join Date
    Sep 2010
    Location
    Boston, MA
    Posts
    97
    I could care less this is for school about the security of it . but for 2d then do a = [1 2 3 ; 1 2 3 ] the ; seperates rows

  9. #9
    Registered User
    Join Date
    Sep 2010
    Location
    Boston, MA
    Posts
    97
    I feel like the problem resides somewhere within my list (vector of matrices). Something about local heap errors occur when I use things from the list.

    But what doesn't make sense to me is that the way vectors are set up when you use push_back then doesn't that auto dynamically allocate the entire class. So that whatever I push into the vector will have different memory than the temp instance in main?

  10. #10
    Registered User gardhr's Avatar
    Join Date
    Apr 2011
    Posts
    151
    Is there a good reason why you're not using an std::vector or similar to manage the memory? Because as it stands you're code isn't exception-safe (not to mention that your problem at hand is most likely related to allocation). If there's some constraint preventing you from doing so I'd recommend that you implement your own vector class (a stripped-down version would suffice) to help simplify memory-management.

  11. #11
    - - - - - - - - oogabooga's Avatar
    Join Date
    Jan 2008
    Posts
    2,808
    gardhr's right of course that it would be more normal and safer to use a vector to hold your data and let it handle the memory allocation/deallocation for you. And a list may be better for your list, instead of a vector. But if you want to keep it the way you have it I've noticed that your addMatrix is, at a minimum, inefficient. You could try something like this instead:
    Code:
    void addMatrix(vector <Matrix> &mL, Matrix &m) {
        for (vector<Matrix>::iterator it = mL.begin(); it != mL.end(); it++)
            if (it->getName() > m.getName()) {
                mL.insert(it, m);
                return; // If it was inserted, then it's done.
            }
        mL.push_back(m); // If it wasn't inserted, then append to end of vector.
    }
    I changed the return type to void since you weren't using the return value.
    The cost of software maintenance increases with the square of the programmer's creativity. - Robert D. Bliss

  12. #12
    Registered User
    Join Date
    Sep 2010
    Location
    Boston, MA
    Posts
    97
    Yes this a lab for school, and requires that we learn dynamic memory allocation with raw pointers. It sucks because my professor barely covered anything related to the topic so I have been learning it through google and help from here.. But thanks I just don't see the problem, could you point out where the code isn't exception safe.

  13. #13
    Registered User
    Join Date
    Sep 2010
    Location
    Boston, MA
    Posts
    97
    Nevermind I FIGURED IT OUT!! I've have spent countless hours staring at the code. And I feel like an idiot that I didn't even try changing this the code for my copy constructor is

    Code:
    //copy constructor call
    Matrix::Matrix(const Matrix &m)
    {
    	int i,j;
    	_row = m._row;
    	_col = m._col;
    	_name = m._name;
    	errorInput = m.errorInput;
    	_mat = new double *[_row];
    	for(i=0;i<_row;i++)
    	{
    		_mat[i] = new double [_col];
    		for(j=0;j<_col;j++)
    		{
    			_mat[i][j] = m._mat[i][j];
    		}
    	}
    }
    and the code when i parse a string is... All i needed to do was get rid of those -1's. hahahaha
    Code:
    //and do a final assignment to the matrix passed to the stream
    	mMatrix._mat = new double *[row-1];
    	for(int i=0;i<row;i++)
    	{
    		mMatrix._mat[i] = new double [col-1];
    		for(int j=0;j<col;j++)
    		{
    			//use isstringstreams to convert the string to a double
    			tempNumString.str(sList.front());
    			tempNumString >> tempDBL;
    			//then pop front to get the next string in line
    			sList.pop_front();
    			//clear the isstrinstream
    			tempNumString.clear();
    			//and finally assign the matrix its value
    			mMatrix._mat[i][j] = tempDBL;
    		}
    	}

  14. #14
    Registered User gardhr's Avatar
    Join Date
    Apr 2011
    Posts
    151
    Quote Originally Posted by omGeeK View Post
    Yes this a lab for school, and requires that we learn dynamic memory allocation with raw pointers. It sucks because my professor barely covered anything related to the topic so I have been learning it through google and help from here.. But thanks I just don't see the problem, could you point out where the code isn't exception safe.
    Basically, whenever you assign an allocation to a raw pointer (except where explicitly "guarded" by a destructor) you're writing exception unsafe code! That is, if an exception gets propagated within the scope of that function, there is no mechanism in place whatsoever to free up the memory. For that reason, the use of a smart pointers/containers is ABSOLUTELY MANDATORY in such cases. Failing to realize the importance of this concept (RAII) will only serve to cause you innumerable headaches in the future, so you'd best commit yourself to it once and for all right now. While you're at it, pass the idea along to everyone you know...including that numb-skull professor of yours!

  15. #15
    Registered User gardhr's Avatar
    Join Date
    Apr 2011
    Posts
    151
    One more important point: This isn't simply a memory leak issue. Consider a situation where you're allocating an object that writes data to a very fragile file; failing to deallocate it properly could well result in a corrupt file! Yes, RAII should be taken very seriously indeed...

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Dynamic memory allocation problem
    By linuxlover in forum C Programming
    Replies: 17
    Last Post: 11-25-2010, 01:11 PM
  2. Dynamic Memory Problem - ADT
    By adamdavis in forum C++ Programming
    Replies: 3
    Last Post: 02-20-2010, 03:51 PM
  3. dynamic memory allocation problem
    By firyace in forum C Programming
    Replies: 4
    Last Post: 05-23-2007, 09:57 PM
  4. Dynamic memory problem
    By *Tom* in forum C Programming
    Replies: 8
    Last Post: 09-11-2006, 10:50 AM
  5. Help with a problem regarding dynamic memory and arrays
    By Michty in forum C++ Programming
    Replies: 5
    Last Post: 07-26-2006, 01:26 PM