tags:

views:

111

answers:

3

I have to fix a typical memory leak, Problem is like that :

typedef std::map<unsigned long,Response> mapType;
class Response
{
public:
 void *dataPtr;
 unsigned long tag;
}

class anyClass
{
 public::

  DataType x;
}

From client i am getting a map of Type mapType , Which has Response object as map->second , As Response object contain a void Pointer.

Please note : Response Class do not know what type of data has been set to void pointer, Also i can't modify Response class to do so , As it is a legacy code and has a great impact :(

Now using map->first ,that i call as Tag,

Using this tag at run time using this tag i come to know about a class anyClass.

Now Response::dataPtr is smae as anyClass::DataType

But:

as class anyClass is one out of N type, So anyClass::DataType differs for each class which i come to know only at runtime.

Please guide me how i can cast a void pointer to type same to anyClass::DataType and can free it

+1  A: 

First, I don't know why do you need to cast these pointers to their original type if it is a memory leak issue. You can simply delete the void* pointer anywhere. Second, you can convert the pointer to a specific type with a simple conditional statement to some specific type compared to the tag, but you need to have the specific code for that pointer in the given context, so in this sense there is not enough information here to solve the problem.

However, if you have a certain behaviour for your responses, call it 'process', you can use inheritance with virtual function to bind the desired behaviour to your object. This is basically the definition of the virtual methods, so use them, even if you need to refactor the old code for this. If there is a problem with the object disposing then it is a matter of a virtual destructor, so the base class should define a virtual dtor, and the using the dynamic_cast(ptr) gives you some type safety at the conversion.

In this way, you don't need the 'tag' member, unless you would like to this by hand with a big 'switch' statement. In this case I can suggest to use crc calculation from the typeid(AnyClass).name() in the tag member.

-- EDIT: There is an other way to store these object without having this issue, I would say a boost::any or similar functionality could solve your problem. If you are storing the data's in a boost any instead of void* pointers you can change the legacy code with a minimal impact. If you delete an entry from the map, it will remove the boost::any's inner value. That should do the trick.

progician
1) i have 500 odd tags .. For performance and maintaince point of view i do not want to write 500 odd condition checks2) If your actual data type is std::Vector<> , assigned to void pointer, deleting void pointer will not free memory of vector
sat
I see. In this case maybe you can use an external tool to create all those switch cases for start, some little awk script or such. Either way, the legacy code need to be revised because no matter where are you using it, you will face with similar problems. Some way or an other, but you have wrap those data types which can be stored in this structure to a common interface, otherwise 500 cases in a switch is cannot be read by humans.
progician
+1  A: 

Given that you mention "legacy" code, but may have some freedom to modify, I would likely suggest that whatever interface provided you the map be extended to include a free-ing function.

Then it could apply the same type logic as when it created the object in the first place.

If that is impossible, then you will likely end up with a case statement and some re-interpret casts like the following pseudo-code:

  switch (type ) {
    case Type1:
      delete reinterpret_cast<Type1Class*>(ptr);
      break;
    case Type2:
      ...

Good Luck

sdg
I agree with you , As currently i am using same logic :) If you see performance ,For each tag i have to iterator through 100 of cases, i wanted to avoid this :)
sat
@Sat - is there any way you can reduce the number of cases by just checking for base classes and delete via those rather than having to check for every type? Of course this would only work if there is a class hierarchy involved and you're not looking at 100 separate types.
Timo Geusch
switch/case is not an iteration. It's a jump -- should be very fast.
Lou Franco
Yes , switch is pretty first, and this is solving my problem
sat
A: 

If your tags are sequential you can build smth. like an array with either function objects or function pointers of their handlers:

template<class T>
void deleteType(void* p)
{
   delete reinterpret_cast<T*>(p);
}

typedef void (deletePtr)(void*);
deletePtr handlers_[] =
{ &deleteType<int> //means: accessed by tag with value 0
, &deleteType< vector<int> > // tag with value 1
, ...
};

//somewhere later:
handlers_[response->tag](response->dataPtr);

This solution requires you to know all types which are possibly stored in response.

If tags are not sequential, you will need to use a map or smth. similar, which involves non-constant complexity.

Hope that helps,
Ovanes

P.S. But if you decide to change the response take a look at boost::variant. Which is exactly what you need, if you were allowed to program generically ;)

ovanes