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 bkrike on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Deleting the void* pointer

Status
Not open for further replies.

Nosferatu

Programmer
Jun 9, 2000
412
RO
I am probably making a basic mistake here, but I just can't figure out why...
I am using a void* pointer in a class (hash table, as some of you probably know) to hold some information. At the end of the program, I delete the hash table, along with the void* pointers.
1. If a specific typecast is not made, the destructor of the object stored in the variable is not called. I guess this would be a normal behavior (rigth or wrong?).
2. When I make the typecast, the destructor is called, but still, I am getting memory leaks reports.

I am using MSVC++6 and I can't figgure out if this is an reporting error (I heard there are some) or is it just me...
Here is a sample:

Code:
class Hash {
  void *data;
  setMember(char* str,void *inData) {
  ...
  data = inData;
}
}

class SomeClass
{ Hash ht;
   ...
}
bool SomeClass::SomeMember()
{ OtherClass* oc = new OtherClass();
   ht->setMember(someString,oc); 
 return true; //!!! no deletion
}

inside the destructor of the hash table, I have:
Code:
Hash::~Hash()
{  if (data)
     delete data;	// does not call the destructor
   //or
  delete (OtherClass *)data; // destructor called.
}

Likesaid, in either case, memory leaks are reported. Anybody can give me a clue of what's happening or how to solve this(Zy, M.E.Slf)? The void pointer should remain as it is, since the data in the hashTable shouldn't have any importance to the HashTable itself.

Thanks! [red]Nosferatu[/red]
We are what we eat...
There's no such thing as free meal...
once stated: methane@personal.ro
 
Well first off if you're going to be casting the void* to OtherClass * in your hash table then it makes sense to not use the void * at all. Using a void* doesn't give you any added functionality, seeing how you cast it in the end anyway. And I'm not sure exactly what you're doing here. Are you actually representing a "hash" node of a hash table? A true hash table should have an array of some sorts that will hold these hash nodes if that is the case. But to answer your first question, yes, casting to OtherClass should call the appropriate destructor. You may wish to put an output statement in the OtherClass destructor to make sure it's being called properly. Other than that your code looks pretty good. Is this the actual code? I'm assuming not. That might be helpful. MY[red]enigma[/red]SELF:-9
myenigmaself@yahoo.com
 
I think it is more of a design issue with the class itself. Why is the HASH class taking care of something "new"ed somewhere else?(Granted this may be as designed) With void pointers you cant call delete on them and that is as intended. When you cast it as the appropriate type I dont know why there is a problem unless it is being deleted elsewhere. Another situation for the memory leak could be your overwriting the void pointer. In the hash table class, i would add to the constructor (if not already there) the line "data = NULL;" and in the set member function i would ASSERT that data == NULL see if you are setting more then once.. if so, your problem may lie here.

The resetting of data may be the issue.

Matt
 
Hey guys!!!
I noticed your repeated observations about the hash table in my other posts as well... I repeat, the code I posted is just a sample.
Of course the hash table has a more complex structure. Anywaym here is how it's declared:
Code:
// The hash element hold for now the pointers to already defined keys
// and it is responsible to delete the objects
class HashElement  
{	
public:
// Public elements
// this is intended to reduce the function calls needed for accessing data 
	
	PHashList	list;
	void *		data;
	HashElement();
	~HashElement();

};



class HashList  
{	
public:
	PHashElement*	indexes;
	HashList();
	~HashList();

};



/******************************************************************************************************
 the index in the hash table:
 takes a character and fetches the correct indexed entry in the list.
 the list has the following entries:
		[0]		=  space character
		[1]		= ! character
		...
		so forth till ASCII character 255
		the next entries belong to :
		[224]	= tab character
		[225]	= LF character
		[225]	= NL character
******************************************************************************************************/

#define	index(c) ((c - 32 >= 0) ? (c - 32) : (223 + (c - '\t')))

class CHashTable  
{
private:
	PHashElement	getElement(const char *src);
public:
	PHashList	table;
	CHashTable();
	virtual ~CHashTable();

	// Hashing functions
	void*			checkItem(const char* src,void *dataIn);	// if the function returns other value than the one passed
												// user should delete the src value (subject to change)
												// If an entry is not found, it is created as the parsing goes on...
												// the data field of the HashEntry is set to <<dataIn>> element
	bool			clearItem(const char *str);		// removes the item from the hash table.
	

	// debug functions
	void			Debug(const char *path);
	void			Debug(FILE* f,PHashList list);
	


};

there it is... There is a little bit of redundancy there, (using a hashList and a hashTable class which contains just 1 hashList), but I thought that the stuff it is better separated this way. Any suggestions are welcomed.
OK. So deleting the void pointer does not do any good.
I totally agree with [red]enigmaself[/red] when he said there is no point to use the void pointer since I cast it anyway. This is NOT my intention, I wanted to see what's happening and, indeed, the appropriate destructor gets called.

To answer Zyrenthian, yes, I do the initialing in the constructor, as a habbit (a good one). I didn't try though the ASSERT stuff. I wonder if you are rigth about this, but I doubt... at least a little; I will give it a shot.

And, the data pointer is supposed to be void, since the hash table is intended to be as generally as possible and that's why the hash table is taking care of something constructed somewhere else. It is just a optimized storage facility, so to speak...

Thus, if I cannot delete the void* pointer the only thing for me to do would be to return all values from the table through a function and delete them somewhere else, in the classes that use the HT...

Thanks for your patience when reading this post... :) [red]Nosferatu[/red]
We are what we eat...
There's no such thing as free meal...
once stated: methane@personal.ro
 
Yeah, you've made pretty much all the points I was going to make yourself. One thing you might try is to make two static integers, one for the constructor and one for the destructor, and init them to 0. Then increment the two variables accordingly whenever a constructor or destructor of your OtherClass is called. If the numbers end up being the same then your memory leak most likely doesn't have to deal with the hash table. If they don't, then at least you have a good direction to go in. As for your hash table structure... Why even have the HashList? I know you said it's redundant but why have it if it's redundant? It's given that the HashTable will have some sort of array or list in it so why create a data type that doesn't do anything but hold another data type? I would say just get rid of it. Trying to track down memory leaks is hard enough. There's no point in making your structure more complicated when you don't gain anything from it. MY[red]enigma[/red]SELF:-9
myenigmaself@yahoo.com
 
One other note: Is it possible that the memory leak is actually in your other class? eg:
Code:
class OtherClass{
  public:
    OtherClass();
    ~OtherClass();
  private:
    char *ary;
}

//**********

OtherClass::OtherClass(){
  ary=new char[1000];
}

OtherClass::~OtherClass(){
}

//**********

Note that even though the OtherClass destructor may be called, it never frees the memory in the char array, thus creating a memory leak. Just another possibility. MY[red]enigma[/red]SELF:-9
myenigmaself@yahoo.com
 
Thanks... The funny thing is that I already tried that static integers stuff some time ago, and it's fine...
The MSVC is pointing me to the place where IT sais that there was some non-deallocated pointer. But that does not help me at all.

I think I am going to create a function in CHashTable that will return all the existing stored objects, in order to be properly deleted. I wonder if I will still have the problem, something like

void *CHashTable::DumpObjects()
{ return nextStoredObject();...
}
...

and in the class where I'm using it:
Code:
SomeClass::SomeMember
{ Object* obj;
  obj = (Object*)hash->DumpObjects();
  while (obj)
  {  delete obj;
     obj = (Object*)hash->DumpObjects();
  }
}
[red]Nosferatu[/red]
We are what we eat...
There's no such thing as free meal...
once stated: methane@personal.ro
 
What exactly is the code that MSVC++ is pointing you to? If all the destructors are being called then it shouldn't be a problem in your Hash Table, thus deleting the objects yourself would be unecessary. MY[red]enigma[/red]SELF:-9
myenigmaself@yahoo.com
 
It is the MFC extension of the new operator. Practically, there is a define (in the debug versions) that points the new function to a cusomised operator that holds the file name and line number where the it was called. The code is:
Code:
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
The DEBUG_NEW is defined in <afx.h>
#define DEBUG_NEW new(THIS_FILE, __LINE__), in debug versions...
and, further more:
Code:
void* AFX_CDECL operator new(size_t nSize, LPCSTR lpszFileName, int nLine);
,
still, if the debug mode is enabled.
The source code for the new operator is published in the afxmem.cpp file in the mcf code and, of course, it uses _malloc_*** functions (malloc_dbg). [red]Nosferatu[/red]
We are what we eat...
There's no such thing as free meal...
once stated: methane@personal.ro
 
uuuh... That's a long story... It's a pretty complex program, used to generate sample content from xml schemas.
I am using for this Xerces C++ SAX.
I don't know if you're familiar with xsd and xml...
I retrieve all the element names, and store a copy in the hashtable, for fast retrieval and then, when the program exits, delete the table. The returned and copied element's destructors ARE called, so i really don't know what's the problem.
The environment reports losses of 4 bytes and 8 bytes blocks. That's pretty strange, since I do the following:
1. get a reference.
2. create a copy of it (4 bytes loss)
3. create a new element, holding the info in the hash table. This element has 2 pointers. 8 bytes loss...

It is pretty obvious what's the memory loss, but I cannot figure it out, since, likesaid, the destructor of the objects are called... [red]Nosferatu[/red]
We are what we eat...
There's no such thing as free meal...
once stated: methane@personal.ro
 
This is kind of out there but do you use any low level commands like calloc and realloc and such? I've found that when using these commands with MFC for some reason sometimes the debugger tells you you have memory leaks. I'm fairly certian that when I came across this problem I didn't have any memory leaks but it still told me I was loosing 4 and 8 bit chunks. I removed the *alloc and replaced it with pure MFC and it works fine now. It also caused my program to hang at the end. There shouldn't be issues with that but it seems as though there are. Just a suggestion. What are the element names stored as? Do you do the copying or do you let a function do it? There are a slu of questions, and no, I don't have much experience with XML and no experience with XSD, so I can't help you in that respect. I hope I've contributed something at least. Also, are you creating a copy of the reference or creating a copy of the actual Object? I assume the object but I just want to make sure. MY[red]enigma[/red]SELF:-9
myenigmaself@yahoo.com
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top