Hm, that sounds like it, but also complicated again, having to define lots of stuff for each possible data type, which can get quite enormous (theoretically, I'd have to define each primitive type, engine class and possible common std::classes). I quess the safety comes at a cost, but I didn't expect that it would need so much extra work per type... I thought there'd be a more general solution. Well, browsing through the web I've found kind of a universal solution, still requiring RTTI but appearantly way faster, which I could apply in a helper function. I'm talking about using typeid. Since I only care about that the types are equal, wouldn't it fare just as well if I just did that?
Thats kind of like what you suggested, just with using RTTI instead of making up a custom system, and thus not having to do a custom . Does that sound reasonable, or are there any drawbacks I'm not seeing right now?
Unfortunately there is a gotcha in that. If I'm not mistaken, typeid returns a const type_info reference which the content of can (will?) change between dll's. With so's on *nix variants, it is probably all nice and safe given the consistent memory model, that is not the case on Windows and I'm almost positive this would end up with multiple type_info's which don't match if passed over dll boundaries. This and the bloat/performance issues with RTTI is why you see so many games that roll their own RTTI replacements, and it is almost always only a problem on Window's because of the memory model. I haven't investigated it myself in a long time, so all I can suggest is testing it in debug/release modes and being very careful before you decide it works.
Unfortunately things are considerably trickier.. Yes, reference counted objects will solve this and by nature you might think that stl takes care of the problem, you'd be wrong and bad things are going to happen. Take the silly example:Now, with all the above, there is one other item to keep in mind when moving to the DLL solution. Memory allocations. I assume you either know about this or have worked around it. Basically unless all the plugins and the executable share a common copy of msvcrt.dll, the memory will come from different memory managers and passing the memory around is unsafe. Even using the std::string stuff is unsafe since the memory comes from different allocators. In the past I
<snippy>
I've definately heard of it, thats why I tried to keep as much as possible internal in my plugins. But what I've also heard so far is that using pointer/references is somewhat safe, like that a std::wstring& will work cross-compiler, since its a pointer and the size will be the same regardless, while only the internal "layout" of the wstring will differ... am I missinformed? Plus, right now my whole engine is a dll that both the plugins and the application have to link against, that seems to be just what you are talking about, isn't it? By god, I don't want to write a dealloc-function for every simply getter I export :/
// in your plugin:
const std::string GetName() const; // Note: non-reference for example..
// in other plugin or somewhere:
const std::string theName = thePlugin->GetName();
When 'theName' leaves scope you are going to trash the allocator list in the calling code. The reference count works as intended, the memory transfers to "theName" as intended, the reference is increased, the temporary goes away and the reference is back to 1. (or a move happens that just puts it directly in theName, either way) Unfortunately the problem is that the allocation took place in the memory space of the plugin and because stl is header only and likely inlined the delete call takes place in the other plugin or program which made the call. Boom, you just leaked in the plugin and corrupted the callers memory.You have a number of ways to correct such things:
1. Guarantee *all* plugins, executables etc link to the dll version of msvcrt.
2. Make a dll library which everything links to which provides the link the msvcrt. (Actually a bit safer than #1 because it guarantee's everyone uses the same version.)
3. Use custom allocators for all STL. The functions must be behind a non-inlinable interface and in a single location. This is a pain in the butt and I don't suggest trying it, too easy to miss things.
Probably more solutions. Sorry to make it sound like such a pain. #1 or #2 are not particularly difficult.