0

I am creating a Lua api for my program. I want to be able to do the following:

void* CreateA()
{
     A* a = new A();
     PointerTypes[a] = A;
     return reinterpret_cast<void*>(a);
}

void* CreateB()
{
     B* b = new B();
     PointerTypes[b] = B;
     return reinterpret_cast<void*(b);
}

void DeleteThing( void* p )
{
     typename type = PointerTypes[p];
     type* t = reinterpret_cast< type >( p );
     delete t;
}

Is there any straightforward way to do this? PS: My application already uses RTTI so it can be used here too.

akaltar
  • 1,002
  • 1
  • 19
  • 25
  • Briefly, no. Once you've thrown away the type information you can't get it back. So any solution will involve storing type information somewhere. – Pete Becker Dec 21 '13 at 15:45
  • 1
    Is there any reason you don't use a common base class? (Which is the case if you want to use existing types you can't alter...) – leemes Dec 21 '13 at 15:54
  • @leemes The types I am using are completely unrelated. They are components. Some are just simple int*, while some are classes, and to expose them to lua, I use lightuserdata(void*). So using a common base class would be very time-consuming. – akaltar Dec 21 '13 at 15:59
  • If you're interfacing to Lua, any reasons not to use LuaBind, for example? – vines Dec 21 '13 at 16:03
  • @vines I want to expose a C-style API to lua for simplicity reasons( its meant to be used by people new to programming, and C-style APIs are much easier to understand), and the other features of LuaBind are not worth it for the added dependency on boost(even tough it can be partially avoided). – akaltar Dec 21 '13 at 16:10

1 Answers1

2

Instead of saving the type in a map (which is not possible because types aren't first class objects in C++) you could store a deleter function in a map. Your factory function then becomes:

void* CreateA()
{
    A *a = new A();
    PointerDeleters[a] = [](void *obj) { delete static_cast<A*>(obj); };
    return a;
}

or with a function template:

template<typename T>
void* Create() // maybe you want to forward c'tor args using variadic template
{
    T *a = new T();
    PointerDeleters[t] = [](void *obj) { delete static_cast<T*>(obj); };
    return t;
}

And then invoke it to trigger the deletion of the object p with unknown type:

void DeleteThing(void* p)
{
    PointerDeleters[p]();
}

The map PointerDeleters should then have the value type std::function<void(void*)>.

A better solution would be (if your design allows it) to use a base class with a virtual destructor; then you can simply delete a pointer to that class without storing any additional information:

template<typename T>
BaseClass* Create()
{
    return new T();
}

void DeleteThing(BaseClass* p)
{
    delete p;
}
leemes
  • 44,967
  • 21
  • 135
  • 183
  • Exactly what I was looking for! One question tough: why use `static_cast` and not `reinterpret_cast`? – akaltar Dec 21 '13 at 15:49
  • See here: http://stackoverflow.com/questions/310451/should-i-use-static-cast-or-reinterpret-cast-when-casting-a-void-to-whatever They allowed to use it in C++11, but it's still considered more dangerous because you can accidentally do more harmful stuff. I prefer `static_cast` unless I have to use `reinterpret_cast`. – leemes Dec 21 '13 at 15:50
  • @akaltar this solution so much resembles the actual virtual method call implementation that I would *very seriously* considered refactoring the code to fit available means, rather than reinvent them.. – vines Dec 21 '13 at 16:01
  • @vines I am bound by the Lua API and I don't see any better way to do this, without introducing otherwise unneeded code and dependencies everywhere in my code. This is meant to be a core system, and it would affect the whole codebase, so I will stay with this. – akaltar Dec 21 '13 at 16:06