Jump to content
  • Advertisement
Sign in to follow this  
AshleysBrain

Tips for designing an SDK with STL (C++)

This topic is 4261 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi, Does anyone have any advice on designing a cross-compiler SDK which uses the C++ STL? Consider the parent application passing a DLL a pointer to a struct which contains a vector. Problems which crop up involve: - Different implementations of STL classes such as vector may be different sizes, offsetting structs and causing wrong data to be retrieved from the parent application. - Different implementations have differently defined routines. You cannot guarantee vector::push_back is gonna work on a vector compiled with a different compiler. Let alone heap problems. - Using iterators on the vectors is probably impossible. The best I've come up with is either writing my own vector implementation (ouch), packaging one STL implementation in with the SDK (ouch), or writing a wrapper which tells the parent app to do the operations on the vector (clunky and no iterators - ouch). Any advice? If you were using an SDK which one would you prefer?

Share this post


Link to post
Share on other sites
Advertisement
I assume by "cross-compiler" you mean "works across multiple compilers" rather than the traditional meaning of "compiles to a different architecture target" or something.

The point of the standard library is that it is standard. It makes certain guarantees that you know will be true across all implementations, unless that implementation is buggy. In which case, you have a larger issue.

You shouldn't really have any trouble with this unless you're trying to do something that is, in and of itself, naughty.

Specifically, your concerns are either wrong (push_back() will always do what it is guaranteed to do, for example) or seem to be general problems of using DLLs rather than the SC++L itself.

Your current example of a parent (I'll use "client") application passing a client-defined structure to your already-compiled SDK (the DLL) is not all that illustrative. There is precious little the DLL, which has not been compiled with any knowledge of the client structure, can do with that structure that is safe and/or legal -- it doesn't matter if the structure contains a vector or other SC++L type or not. Since the DLL code did not have access to the structure definition at compile time, it cannot know its size nor can it access any of its elements "natively" via operator->. The only way to access elements of the structure would be via ugly casting tricks, which can be easily broken by the padding or alignment settings of the compiler building the application, or by the presence (or abscence, depending on the DLL's assumptions) of a virtual table pointer within the instance.

Can you clarify your example? Specifically with a structure you're thinking of passing and how the DLL is supposed to use it. It may be that what you're trying to do is just plain poor design.

Share this post


Link to post
Share on other sites
Quote:
Original post by jpetrie
I assume by "cross-compiler" you mean "works across multiple compilers" rather than the traditional meaning of "compiles to a different architecture target" or something.

The point of the standard library is that it is standard. It makes certain guarantees that you know will be true across all implementations, unless that implementation is buggy. In which case, you have a larger issue.

You shouldn't really have any trouble with this unless you're trying to do something that is, in and of itself, naughty.

Specifically, your concerns are either wrong (push_back() will always do what it is guaranteed to do, for example) or seem to be general problems of using DLLs rather than the SC++L itself. Perhaps you should clarify with an example.


Judging from the OP's post I think he means that one object file (A.DLL for example) is compiled with compiler A and another object file which links to the first (B.EXE for example) is compiled with compiler B.

To the OP: The sad truth is, you can't. There is no standard C++ ABI.

Quote:
writing my own vector implementation

Won't neccessarily work, because the compiler doesn't have a standard way to represent a type in memory, so one compiler might pad, another might not, one might use vtables while another doesn't, etc.

Quote:
packaging one STL implementation in with the SDK

You mean like compiling a portable STL version? That won't work eiher, padding, vtables and other stuff is still an issue. Also DLLs can't really export classes, what some compilers do is a compiler-specific hack which not all compilers support (some do use the same hack though).

Quote:
writing a wrapper which tells the parent app to do the operations on the vector

Won't work for the same reason as previously mentioned.

Generally the best way is to distribute the source, and as many make files/solutions/projects or whatever your IDE calls them as possible.

Share this post


Link to post
Share on other sites
Quote:

Judging from the OP's post I think he means that one object file (A.DLL for example) is compiled with compiler A and another object file which links to the first (B.EXE for example) is compiled with compiler B.


Your points are all valid in general, but a DLL has a specific format (the PE format) so that an SDK/external library compiled into a DLL via one compiler should be usable by a client application compiled with another. The actual method of using the DLL might vary (the import library may be a different format, et cetera).

For clarification, the concerns I laid out (which I did during an edit while CTar was replying to my original, shorter post) apply specifically to DLLs, not to object or ABI formats in general.

I agree with CTar that all three of the OPs proposed "solutions" are unworkable, for a variety of reasons, and I'd still like to see a more concrete example of what's (s)he wants to do with this client-side structure within the DLL.

Share this post


Link to post
Share on other sites
CTar is on the right track.

This is meant to be a flexible SDK, with access to parent application ("B.exe") vectors. Ideally, the client DLL would have normal access to the vector, being able to push_back, erase, iterate etc. but obviously we have to workaround.

For now, I've come up with this:
- The DLL is passed a class with pure virtual functions. The DLL calls the function to do ordinary vector tasks like push_back.
- The EXE derives a class which stores a pointer to a vector, then defines said function to push back the parameter. This is the class passed to the DLL.

This appears to work OK, and should be robust to packing/differing STL implementations. It comes with its problems though.
- Are virtual calls at least fairly standard across compilers?
- I can wrap this functionality in a class, but its not much better - I need a different class to represent vectors of different types!
- Whats the best way to deal with sizeof(vector) varying and offsetting other members? I could move all vectors to the bottom of the structs, or I could replace them with a char array of the size defined by the parent application's compiler.
- Is there just a better way?

Share this post


Link to post
Share on other sites
When you use a DLL, you have to hide all the implementation details and expose only functions and basic data types. Anything that the DLL creates (malloc or new) also ought to be destroyed by the DLL. The DLL and main executable can have seperate free-stores.

So if you want a interoperable vector, you need to make functions that operate on an opque pointer (or index) to an actual STL vector - the wrapper idea.

Since it is a DLL, you can also look at COM which (among other things) provides a ABI for C++ for Windows.

Share this post


Link to post
Share on other sites
You might want to check out the book 'Imperfect C++'. It goes into a fair amount of detail on this and other related issues.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

Participate in the game development conversation and more when you create an account on GameDev.net!

Sign me up!