Alternatives to passing objects between modules
I am under the impression that, for a variety of reasons, it's not safe to pass standard library objects (templated ones in particular) between modules when they could be compiled with different versions of the standard library or different compilers. My goal now is to find a viable solution to this, particularly in the case of shared pointers and strings.
The possible solutions that come to mind include:
- C and other primitive types that never change (not possible, as more complex types are required)
- Types from a standardized library, either:
- Custom implemented (which requires adding string and such classes, which honestly sounds horrible)
- Some external library that already provides such things (first thought is Boost, but even without the bloat that involves, it seems too template-heavy to work)
- Some magical circumstance actually makes it safe (in all cases but shared_ptr)
The real problem appears to be things such as shared pointers which depend heavily on templates.
The question of whether passing 开发者_如何学Cstandard library objects and such has been asked many times, and always comes back to being a Bad Thing in some cases, but an actual solution that doesn't involve writing tons of code that's already been done dozens of times seem to be rare.
Is there a solution to this that does not involve implementing internal reference counting and custom strings, or is that just a price that must be paid for cross version/compiler/platform safety?
There is no solution besides breaking down your classes into their trivial member types, and passing them each individually, if you are using different compilers to compile your modules. If you use the same compiler and only different versions of it, it may very well be, that the modules are already compatible (unless the ABI changed, like class layout etc.). Besides that the ABI of the Standard C++ Library types could have changed, in this case, you can workaround it by using a third-party library instead, which provides the same functionality, but guarantees binary compatibility (e.g. Qt does that). But this isnt a perfect solution either, since the library used by your main program must be newer than the library version linked by all modules. But this is often sufficient, because most often you only need that old plugins continue to work with a new version of your program, and not that new plugins work with a old version of your program.
The issue is not with passing objects between different modules, this works just fine. The thing that you need to enforce is that objects created by module X are always deleted by module X.
You can make this work if you provide wrapper functions for any operations that require memory allocation/deallocation, so that you have control over what module executes these functions.
For example, this is the header class of a class that is memory safe:
class SomeObj {
private: // private ctor/dtor to prevent outsiders from using them
SomeObj() {}
virtual ~SomeObj() {}
public:
static SomeObj* create();
void destroy();
};
And here is the implementation:
SomeObj* SomeObj::create()
{
return new SomeObj();
}
void SomeObj::destroy()
{
delete this;
}
With a class setup in this way you are forcing anyone that creates or destroys the object to go through create()
and destroy()
, so the module that has these functions will always be managing the memory for this class. Note that create()
and destroy()
cannot be inlined.
For more complex classes like the STL containers it gets a little bit trickier, as you will need to wrap more functions besides create and destroy, but it can be done.
Assuming same compiler is used for both modules, and no one will deploy newer version of only one module...
I think you can pass objects across module (by modules I mean DLLs + main EXE) boundaries, the problem is only in the fact that heap allocation and static variables cannot be relied upon.
So if you're passing read only structure, everything should be fine.
But as soon as you start allocating, reserving, etc, etc. Things WILL break (different heaps, no statics).
Might be mistaken though, so please no down-votes.
精彩评论