Hi,
I've now spent hours looking at this and no joy, wondering if any of you guys can help.
I am passing an object that uses dynamically allocated memory into a method, but for some reason when it finishes my original object has changed/been destroyed.

header file:

class Multiset  
{
public:

	Multiset();					//default constructor for multiset
	virtual ~Multiset();			//default destructor for multiset
	
	Create(int newsize);		//Creates an array of a given size.
	
	virtual bool AddElement(int ElementValue,int Position);	//Adds an element to a given position in the array.
	int &ReadElement(int index);			//Returns Address of element
	
	bool IsMember(int Element2Check);	//Checks if a given element is a member of the multi/set
	int GetCardinality();				//Returns the number of elements in a multi/set
	bool IsSubset(Multiset MSet2Check);	//Returns whether the current multi/set is a Subset of a given multi/set


protected:					//Only derived classes should have access
	int *data;				//Pointer to int
	int size;				//Holds the size of the Array
	bool ArrayExists;

};

Implementation of Class MultiSet:

/////////////////////////////////////////////////////////////////////////////////////
// Construction/Destruction
/////////////////////////////////////////////////////////////////////////////////////


Multiset::Multiset()
{
ArrayExists = false;		//Memory has not yet been allocated for the array.
}


Multiset::~Multiset()
{
	ArrayExists = false;	//Memory has been de-allocated for the array.
	delete[] data;
}


/////////////////////////////////////////////////////////////////////////////////////
//
//  Create()
//  Method to create an array of a given size. (Largest size is determined by int)
//  Passed IN : Int Size  (Size of array to be created)
//	Passed OUT: Nothing
//
/////////////////////////////////////////////////////////////////////////////////////

Multiset::Create(int newsize)
{
	// set size to newsize and allocate memory
	size = newsize;
	data = new int[size];
	
	// returns 0 if new failed, otherwise returns 1
	if (data == NULL){
		cout << "Not enough memory available";
		exit(-1);
	}
	else
		ArrayExists = true;
}

//Multiset object passed in to this method,original gets destroyed!!
bool Multiset::IsSubset(Multiset MSet2Check){

	int i=0,j=0;
	bool FoundInInner = false ;
	
	
	if (size > MSet2Check.size)
		return false;		//Cannot be a Subset as it is larger than MSet2Check
	else				  //Work out if it's a subset of MSet2Check
		for (i=0; i<size; i++){
			for(j=0; j<MSet2Check.size; j++){
				if (data[i] == MSet2Check.data[j]){ 
					FoundInInner = true;
					MSet2Check.data[j] = Reset;		
					break;							
					}
				else
					FoundInInner = false;
				}	
			if (FoundInInner == false)
				return false;
			else 
				{
				 j = 0;		//j counter is reset to 0 for next i loop
				 if (i == (size - 1)) 
	    			return true;
				}
			}

}

Sorry for the big block of code guys, basically when I use mySet1.IsSubset(mySet2) the original mySet2 values all change on leaving the method IsSubset. It is calling the destructor on leaving and then I think it is killing my original object,
How do I get it to leave my passed in object alone!!??
Thanks for your time guys.

Recommended Answers

All 6 Replies

It is not calling distructor, you are passing object by value therefore you do not see the change in values of the passed object.
Declare the member function as

bool IsSubset(Multiset &MSet2Check);
//Multiset object passed in to this method,original gets destroyed!!
bool Multiset::IsSubset(Multiset &MSet2Check){

	int i=0,j=0;
	bool FoundInInner = false ;
	
	
	if (size > MSet2Check.size)
		return false;		//Cannot be a Subset as it is larger than MSet2Check
	else				  //Work out if it's a subset of MSet2Check
		for (i=0; i<size; i++){
			for(j=0; j<MSet2Check.size; j++){
				if (data[i] == MSet2Check.data[j]){ 
					FoundInInner = true;
					MSet2Check.data[j] = Reset;		
					break;							
					}
				else
					FoundInInner = false;
				}	
			if (FoundInInner == false)
				return false;
			else 
				{
				 j = 0;		//j counter is reset to 0 for next i loop
				 if (i == (size - 1)) 
	    			return true;
				}
			}

}

Call this method as you were calling it previously.

Hi,
Thanks for the suggestion, sorry maybe I didn't explain myself very well, the problem is that the values are changing and I don't want them to. That is why I thought that by passing the object by value, it would leave the original object alone...but it doesn't. When I step out of IsSubset my original object is full of random values. Any ideas?
Thanks.

Because of in class
int *data;

and "MSet2Check.data[j] = Reset;" in the method. It changes the value memory location pointed by data member of MSet2Check.

There are couple of solutions
1)Prepare a deep copy of MSet2Check in the function and use it inside the function. You may like to overload '=' operator and
Multiset localobj = MSet2Check and operate on localobj ie "localobj .data[j] = Reset;"
2) If you dont want MSet2Check to change why do you do "MSet2Check.data[j] = Reset;" ? Better change the decleartion of the method as
bool Multiset::IsSubset(const Multiset MSet2Check) ; and nevre do "MSet2Check.data[j] = Reset;" anyways; I don't see any reason of doing this.

Above solutions will help not changing the object being passed. Caller object is certenly going to change. I hope as the name suggests "IsSubset" should not change either caller or callie.

For that you need to modify your logic in the member function and declare it as
bool Multiset::IsSubset(const Multiset MSet2Check) const; and overload ‘=’ operator to prepare deep copy and use solution 1.

Thanks again,
Yes it is true that I do not want to change my original object. From what you have been saying about creating a "deep copy", it has reminded me that I think i need to make a copy constructor to allocate memory for the local object. At the moment I think it is using the same address for the local object as it is for the original object, then when it leaves the function it is freeing up both local and original as they have the same address.
I think I am on the right track now, thanks for your suggestion, gave me a few ideas to try anyway. Let me know what you think!

What do you mean by original object the one used to call the function or the one which is passed or both ?
You need a copy constructor indeed.
Always declare a copy constructor and an assignment operator for classes with dynamically allocated memory.

Ya, by original object I mean the passed in object. I started coding a copy constructor now, think this should do it, I understand now what you mean by overloading the = operator. That way I can 'really' copy my objects.
Thanks for your suggestions, it put me on the right track.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.