Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations strongm on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

destruction before return 2

Status
Not open for further replies.

icrf

Programmer
Dec 4, 2001
1,300
US
I have a matrix class with a memory deleting destructor and a multiplication operator overloaded. When it multiplies two matricies, it checks their sizes to see if they can be multiplied, then creates a new matrix object of appropriate dimensions to store the result, which it returns at the end.

It performs all the math perfectly well, as the debugger tells me when going through, but it runs the destructor of the local object "result" BEFORE it returns it (a copy of it). The copy that it returns is empty and crashes the program. This is my first time back in C++ after awhile, and from what I remember before, I had similar problems, though this is the first time I've caught it freeing before returning. If the "delete" statement are removed from the destructor, everything works fine.

I've run this through gcc and it works just as expected, but in VC++ 6.0 it crashes with the same code. Why does it destroy before returning?

Potentially relevant code:
Code:
template <class itemType> class matrix
{
  public:

  // constructors/destructor
    matrix( int rows, int cols );                             // size rows x cols
    matrix( int rows, int cols, const itemType & fillValue ); // all entries == fillValue
    ~matrix( );                                               // destructor
	int print();

  // assignment
    matrix & operator = ( const matrix rhs );
	matrix operator * ( const matrix rhs );

  // accessors
    int numrows( ) const;                             // number of rows
    int numcols( ) const;                             // number of columns
	int set(int i, int j, itemType k);                // set value at i,j to k
	itemType get(int i, int j) const;                 // get value at i,j

  private:

    int myRows;                             // # of rows (capacity)
    int myCols;                             // # of cols (capacity)
    itemType **myMatrix;                    // the matrix of items
};

template <class itemType> 
matrix<itemType>::matrix(int rows,int cols,const itemType & fillValue )
{
	int i,j;

	myRows = rows;
	myCols = cols;

	myMatrix = new itemType *[myRows];
	
	for(i=0;i<myRows;i++)
	{
		myMatrix[i] = new itemType[myCols];
	}

	for(i=0;i<myRows;i++)
		for(j=0;j<myCols;j++)
			myMatrix[i][j] = fillValue;
}

template <class itemType> 
matrix<itemType>::~matrix ()
{
	int i;
	cerr << &quot;I'm killing stuff...&quot; << endl;
	for(i=0;i<myRows;i++)
	{
		delete [] myMatrix[i]; //if removed, works fine
	}
	delete [] myMatrix; //if removed, works fine
}

template <class itemType> 
matrix<itemType> matrix<itemType>::operator * ( const matrix<itemType> rhs )
{
	// check multiplicability
	if(myCols != rhs.myRows)
    {
		cerr << &quot;Dimension mismatch, cannot multiply&quot; << endl;
		exit(1);
	}

	//make new matrix of correct size, initializing everything to zero
	matrix result(myRows,rhs.myCols,0);

    int i,j,k;
	for(i=0;i<myRows;i++) //each row in lhs
	{
		for(j=0;j<rhs.myCols;j++) //each col in rhs
		{
			for(k=0;k<myCols;k++) //each element in rhs row and lhs col
			{
				result.set(i,j,(myMatrix[i][k] * rhs.myMatrix[k][j])+result.get(i,j));
			}
		}
	}
	return result;
}
----------------------------------------------------------------------------------
...but I'm just a C man trying to see the light
 
Not exactly sure, but try overloading:
Code:
template <class itemType> 
matrix<itemType> operator * ( const matrix<itemType> &lhs, const matrix<itemType> &rhs )
{
}
instead.
 
Nope, same deal. Crashes in MSVC++ and fine in GCC. I imagine the theory with the change was making it not a member function, hence, doing away with dealing with the this reference?

The problem is still what I'm pretty sure is the object getting destroyed before it's returned. Any idea why this problem is happening, like some error in my code or nuance with the MS compiler? The code is correct so far as I can tell, and works elsewhere, why not here?

As a side note, anyone know of a good, free online code reference with basic meaning outlines and syntax? Kind of like perldoc.com is for perl. ----------------------------------------------------------------------------------
...but I'm just a C man trying to see the light
 
I am just as confused as you are. A good reference would be apmatrix by the collegeboard.

You can get it at:

But thing is, that doesn't support *... It does however have a apstring that supports +, but that's still not the same. I have no idea..

This is completely odd..

Haha - I'm going to go completely mad. It runs through the function, but after the return results, it goes nuts and starts killing everything.

I'll be looking for whoever has a reply to this. :p I'm completely stumped.

Code:
creation: 0
creation: 1
creation: 2
I'm killing stuff...
stuff id:2
I'm killing stuff...
stuff id:2
  <CRASH>
I'm killing stuff...
stuff id:1
I'm killing stuff...
stuff id:0
Press any key to continue

It can't find myMatrix anymore in the 3rd creation of it (the one in your *)... Does MSVC++ have something wrong with it's scoping principles? --> passes it out and then tries to kill it? *sigh* I don't know. I'm going to give my head a little rest. Good luck. I'll look at it again some other time.
 
Yeah, I think I'm going to try this in Visual Studio.NET today in a lab, anyone out there with 6.0 SP1 give it a try? I don't know if this is a bug that they fixed at some point or if I'm still just a little crazy.

I even went out and downloaded the Intel C++ compiler last night, it can be embedded into visual studio. It didn't come with a large set of standard header files, though, so it's still using MS's and still crashing. I guess that just means I can crash even faster now.

For anyone really interrested, whatever my current WIP is will be up on
there's a .cpp and a .h file up there. Even a partial copy of it in perl, too :) ----------------------------------------------------------------------------------
...but I'm just a C man trying to see the light
 
I think you need a proper copy constructor.

The operator = can't be used since it's argument is not a reference.
It HAS to be a reference, since passing by value will require making a copy which will require a copy constructor which .....

Since you are dealing with potentially large chunks of memory, I would also pass parameter to operator * by reference.




/JOlesen
 
A copy constructor...how do I miss such fundamental concepts? Definitely worth a star.

It most certainly fixes everything. I didn't know that an object can't just be copied, like structs could. At the basic level, it's still just a block of memory, no?

Is there any reason the * overload should be a member function or not? Both operands will always be class objects and it's not a commutative operation. ----------------------------------------------------------------------------------
...but I'm just a C man trying to see the light
 
Thanks icrf,

C++ certainly has a default copy constructor which will be used (I think ....). It will even copy the pointervalue(s), but the memory which the pointers point to is NOT copied, but released during the destruction of the original object ... thus things goes very wrong.
/JOlesen
 
a tad off topic - who thinks 'flerchinger' is the world's worst name? >=)

my code is still in 2 states
1. w/ deconstructor, crashes
2. w/o runs, but with memory leak.
 
ZAO, man, first, play nice, second, we need more info here to answer anything. I'll take a look at it around 4:30 today and see if I can't figure some of that stuff out. Yes, without a deconstructor and making hundreds of objects a second, yeah, you'll leak a tad of memory. ----------------------------------------------------------------------------------
...but I'm just a C man trying to see the light
 
Hi,

You have a pointer to some allocated memory in your class. This almost always means you need to provide:
1. A copy constructor,
2. An assignment operator

Because the default copy-constructor and assignment operator only do shallow copy - they copy the pointer, but not the content the pointer points at.

Since both functions (copy-constructor and assignment operator) are almost identical, you can write a private helper function that does the actual copying:
Code:
    template <class itemType> class matrix
    {
    public:
        ...
        matrix(const matrix& rhs);
        
        matrix& operator=(const matrix& rhs);

    private:
        void Copy(const matrix& rhs);
    };

    template <class itemType> 
    matrix<itemType>::matrix(const matrix<itemType>& rhs)
    {
        Copy(rhs);
    }

    template <class itemType>
    matrix<itemType>& 
    matrix<itemType>::operator=(const matrix<itemType>& rhs)
    {
        Copy(rhs);
        return *this;
    }

    template <class itemType>
    void matrix<itemType>::Copy(const matrix<itemType>& rhs)
    {
    ...
    }
[\code]

Secondly, I would like to suggest implementing operator* as non-member function.  You can implement it as a global function or a friend function.  The function should return a const object.  

Another tip:  If you want to implement operator*=, implement it as member function, and implement operator* in terms of operator*=.  This safe you writing duplicated code:
[code]
    template<class itemType>
    const matrix<itemType> operator*(const matrix<itemType>& rhs, 
                                     const matrix<itemType>& lhs)
    {
        return matrix<itemType>(rhs) *= lhs;
    }


    template<class itemType> class matrix
    {
    public:
        matrix& operator*=(const matrix& rhs);
    };

    template<class itemType>
    matrix<itemType>& 
    matrix<itemType>::operator*=(const matrix<itemType>& rhs)
    {
        // actual multiplication code here...
    }
[\code]

HTH
Shyan
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top