Archived

This topic is now archived and is closed to further replies.

kill

boost::any, VARIANT, void* ...

Recommended Posts

If someone doesn''t know, boost library has an "any" class that can be used as a type safe alternative to void*. The only problem is that it''s not exactly portable across dlls created with different compilers because it uses RTTI. I''m trying to find a good alternative... I''m implementing a state manager class. Something similar to Set/GetRenderState in D3D that takes a state as a first parameter and a value as a second. D3D, however, doesn''t take anything that''s more then 4 bytes so a LONG is good enough. I''d like to pass more complex data types. One alternative is boost::any, but as I mentioned it''s not portable across dlls compiled with different C++ compilers. I could simple pass a void* and a size of the buffer so the data would simply be copied and interpreted later on, but that''s not exactly type safe, plus it will involve allocating memory on the heap. Another alternative is to use a structure similar to COM''s VARIANT. The limitation of VARIANT is that only few data types can be passed. Also, later on I''d like to make my classes usable by scripting languages, so I have to keep that in mind. I''m kind of stuck... Can someone make any suggestions or give me some ideas? Any feedback is welcome. Thanks.

Share this post


Link to post
Share on other sites
Well, this may be a silly question...

Why are you using multiple compilers?

Sometimes RTTI is closely associated with the name-mangling scheme of a compiler. If RTTI doesn''t work, then the name-mangling probably won''t either - in which case you can''t use C++ DLLs compiled using different compilers.

This is a bit of a rat''s nest as there is no definition to the standard on name-mangling or RTTI.

If you can use one compiler that is definately your best bet - for more reasons than just these ones. In which case you could use the boost::any class.

Share this post


Link to post
Share on other sites
I have to say this again and again.

"C++ and dlls don''t mix well together. Dlls are designed and meant for C. If you must, use COM or recompile for each compiler. If you want total platform independence, you have to forgo dynamic loading totally."

Perhaps this should be sticky or in faq.

Share this post


Link to post
Share on other sites
quote:
Original post by kill
ummm. Void, COM uses DLLs.



But COM enforces the format of the vtable and calling conventions so that you don''t have to worry about different compilers. Also, COM would make a scripting language really easy, because it supports reflection pretty much out of the box via the IDispatch interface.

If I had my way, I''d have all of you shot!


codeka.com - Just click it.

Share this post


Link to post
Share on other sites
quote:

But COM enforces the format of the vtable and calling conventions so that you don''t have to worry about different compilers.


This is exactly why it''s so easy to implement COM components using C++ classes: any C++ compiler that supports COM has the same vtable layout.

quote:

Also, COM would make a scripting language really easy, because it supports reflection pretty much out of the box via the IDispatch interface.


It''s not really out of the box... You still have to implement all the dirty details of IDispatch. Type libraries make it easier but it''s still a pain...

Share this post


Link to post
Share on other sites
quote:
Original post by kill
This is exactly why it''s so easy to implement COM components using C++ classes: any C++ compiler that supports COM has the same vtable layout.



This is not necessarily true.

the COM interface layout is identical to Microsoft''s vtable layout. The vtable layout, as far as I know, isn''t part of the c++ standard. Just the behavior of it is.

And remember, COM is completely Windows dependent at the present time.

Share this post


Link to post
Share on other sites
quote:
Sometimes RTTI is closely associated with the name-mangling scheme of a compiler. If RTTI doesn''t work, then the name-mangling probably won''t either - in which case you can''t use C++ DLLs compiled using different compilers.

quote:
"C++ and dlls don''t mix well together. Dlls are designed and meant for C. If you must, use COM or recompile for each compiler. If you want total platform independence, you have to forgo dynamic loading totally."

That''s not quite correct. C++ and DLLs mix perfectly well together. You just have to keep in mind a few rules. Name-mangling can be disabled by using an extern "C" specifier. Class internals can be hidden from the interface of the DLL and a simple factory function can be used to construct all kinds of classes.

Total platform independence is also possible. Of course, just as you have to recompile a main program for different platforms, you''ll have to recompile your DLLs (or shared objects, or shared libraries or whatever).

Of course, the only drawback is that if you want to be independent of platform and compiler, you can''t use RTTI and exception handling... That''s sad, but for RTTI, a custom system isn''t difficult to implement. Exception handling on the other side can''t be implemented with other means, but it''s possible to live without them.

Here is an article on how to do Binary-compatible C++ Interfaces with DLLs.

Share this post


Link to post
Share on other sites
quote:
Original post by kill
It''s not really out of the box... You still have to implement all the dirty details of IDispatch. Type libraries make it easier but it''s still a pain...


That''s why I said almost out of the box. If you''re using ATL and only implement one interface, you do get it for free though.

If I had my way, I''d have all of you shot!


codeka.com - Just click it.

Share this post


Link to post
Share on other sites
quote:
Original post by Magmai Kai Holmlor
When would you ever only implement one interface? (IUnknown?)
Or even just two interfaces is fairly uncommon.



Well, your own interface would inherit from IUnknown, so you that doesn''t count. And you can also implement IErrorInfo (for access to error information from VB and such) and still get ATL to implement IDispatch for you. So it''s really not that bad.

Still, it''s not that hard to implement IDispatch yourself, once you get the hang of it

Anyway, this isn''t really the point of the post and we''re getting a bit off-topic. Personally, I think the simplest solution is to use COM (or some other component model if you can''t stand the idea of using something from Microsoft).

If I had my way, I''d have all of you shot!


codeka.com - Just click it.

Share this post


Link to post
Share on other sites
i am planning to make a console (actually, i''ll just use the one from my older project ), and here''s how i will allow to change vars. a function, RegisterVar(void* pVar, SOME_ENUM_WITH_ACCEPTABLE_VAR_TYPES oVarType, std::string& sVarName), will be called for every variable i want to be listed in the console. so when you type something like brightness 0.6 in the console, and the code had a call to CConsole::GetSingleton() /* */ ->RegisterVar(&fBrighness /* will be inside another class of course */, CConsole::VARTYPE_FLOAT, (String)"brightness");, then it will convert the 1st param (0.6) into a float and assign 0.6f to (*fBrightness). well, that''s how i was planning of doing it, not sure if it''ll work out that way (maybe i need to do something other than void*, i don''t know right now). maybe that will help you.

---
shurcool
wwdev

Share this post


Link to post
Share on other sites
shurcool: You might want to design a more general solution. Just changing a variable is ok when it''s referenced by other classes every once in a while, but it''s hardly an elegant approach. Also, sometimes you just can''t simply change a variable, you need to actually call a function in order for the change to take place. Also, you might want to be able to call methods of your classes through the console...

Origin: I couldn''t have described my thoughts on the matter better

Share this post


Link to post
Share on other sites
well, what about function pointers? that should do it, right?

and about a more general solution. i don''t think i need one, because console is meant to let u change general vars, like max players, ur own name, brightness, etc. nothing too complicated. i think it should do for my purposes.

Origin: why isn''t exception handling portable? =\ i thought it was a c++ standard. doesn''t gnuc (for linux) support it?

---
shurcool
wwdev

Share this post


Link to post
Share on other sites
shurcool: the problem is that in order for a feature to be portable it has to be standardized at two levels. First is the syntax and functionality level. Another words the syntax and what will happen is consistant across all platforms. The second level is the binary/implementation level. There are many ways to implement inheritance, RTTI, exceptions, etc. Unfortunately, the C++ standard only talks about the first level. That means that exceptions can be implemented differently by different compilers. Consequently, if you wrote a dll in a Borland compiler that throws and exception and try to catch it in an executable compiled by a Microsoft compiler it won''t work because the exceptions are implemented differently. Your program will simply crash.

Share this post


Link to post
Share on other sites
kill, what u said makes perfect sense, but i wasn''t talking about dll''s. so it should work fine on any compiler, it''s just that the binary code that it''ll produce will be different. but that doesn''t matter to me, right? i think so. thanks for ur explanation.

---
shurcool
wwdev

Share this post


Link to post
Share on other sites
quote:
Original post by Origin
That''s not quite correct. C++ and DLLs mix perfectly well together. You just have to keep in mind a few rules. Name-mangling can be disabled by using an extern "C" specifier. Class internals can be hidden from the interface of the DLL and a simple factory function can be used to construct all kinds of classes.

Total platform independence is also possible. Of course, just as you have to recompile a main program for different platforms, you''ll have to recompile your DLLs (or shared objects, or shared libraries or whatever).



Extern "C" is not C++. Can you do virtual methods with extern C?

I suppose you mean recompiling for each compiler, which defeats the whole idea of dlls.

Suppose you export this class.

#include <string> // THIS IS ALREADY A PROBLEM

__declspec(dllexport) class C
{
std::string my_string_;
};


You are already heading for trouble because clients might be linking in a different version STL implementation of the std::string in their main program. Some uses reference counted strings, others don''t. You will get total undefined behaviour.

The class by itself, is not portable even across the same compilers using different libraries. You have to recompile it always when you switch compilers/libs, which already defeats whole purpose of dlls.

Share this post


Link to post
Share on other sites
Void: Please read my post again and have a look at the attached link. It is right that directly exporting classes and exposing platform-specific details (std::string) will cause a whole lot of problems. But you won''t have them if you only expose the public interface of your class and use an extern "C" declared factory function.

Share this post


Link to post
Share on other sites
quote:
Original post by Origin
Void: Please read my post again and have a look at the attached link. It is right that directly exporting classes and exposing platform-specific details (std::string) will cause a whole lot of problems. But you won''t have them if you only expose the public interface of your class and use an extern "C" declared factory function.


void means if you use ANYTHING from a classpointer to a stringpointer, or any c++ only object from and to the interface and vice versa the client, you get major problems as the binary interfaces don''t match. in the end, you have to give over char* and length, as no other string type is garantuied to be binary compliant over compilers.. and classes you can''t give over that easy as well (except the compilers use a pseudo binary standart, like in com is done i think (think about it, you create the derived object with an implemntation that has a local vtable (meaning its stored per object) and you _USE_ it some implentation that uses a global vtable per type and a pointer to it (vc for example, most others i know as well..), you simply _CANT_ call any of the methods of this object..)

"take a look around" - limp bizkit
www.google.com

Share this post


Link to post
Share on other sites
quote:
Original post by Origin
Void: Please read my post again and have a look at the attached link. It is right that directly exporting classes and exposing platform-specific details (std::string) will cause a whole lot of problems. But you won''t have them if you only expose the public interface of your class and use an extern "C" declared factory function.


Rite you are. A well summarized article but it missed two points - Copy ctor and assignment operator. The dll should have declared them to avoid the compiler from generating an implicit copy. I should say also default ctor as well.

What happens if your interface needs to return a type that has a std::string or std::vector as a member? You can''t, and your class design is severly impeded by the dll constraints.

There lies the problem with using C++ and dlls. You can''t expose anything other than POD types. Also you can''t have virtual members. You can only use them as an interface/factory pattern and isn''t that just a better version of C?

Without templates, virtuals, STL, exception safety, I wouldn''t call that C++.

Share this post


Link to post
Share on other sites
First of all, STL is not part of the language, it''s just another API. Standard, but an API. It has very little to do with the language itself, just an API that uses the language facilities.

Second, what exactly do you mean you can''t have virtual members with the dll scheme? The virtual table implementation is standardized by COM. All self respecting C++ compilers support COM, which means you can safely have virtual members.

So, the only two features you can''t use is RTTI and exceptions, and these two aren''t used in C++ that often anyway. STL is not part of the language, and it should be exposed in the interfaces anyway. Any iterface that explicitly exposes an STL container is IMO a poorly designed interface.

Share this post


Link to post
Share on other sites
quote:
Original post by kill
Second, what exactly do you mean you can''t have virtual members with the dll scheme? The virtual table implementation is standardized by COM. All self respecting C++ compilers support COM, which means you can safely have virtual members.



You can''t do this and expect the dll to work on another compiler.

__declspec(dllexport) class C
{
public:
virtual void Method(); // implementation in dll
}


COM is a different story. It is an implementation specification that works only on win32. It uses really ugly macros to bypass the vtable. From what I can see from the macros, it is essentially doing some vtable calculations to turn the C++ calls into extern C methods.

quote:

So, the only two features you can''t use is RTTI and exceptions, and these two aren''t used in C++ that often anyway.


Says who? You are talking about programs using C++ as a better C only.

Programs who neglect exception safety are

1. not robust. Leaks resource/memory during a crash, assertion failure...ie. when something exceptional occurs.

2. Harder to maintain as error checking using return value gets messy. Usually these programs neglect error checking too.

Why do you think many programs nowadays (esp windows) have security problems like buffer overflow, crashes when error etc.

Share this post


Link to post
Share on other sites
quote:
COM is a different story. It is an implementation specification that works only on win32.

No it doesn''t. COM exists on a variety of platforms, including most UNIXes.

quote:
It uses really ugly macros to bypass the vtable.

The COM headers have macros that either construct a v-table with proper v-table lookups (for use with C++), or a set of structs that match the v-table (for use with C). They don''t bypass the v-table.

quote:
From what I can see from the macros, it is essentially doing some vtable calculations to turn the C++ calls into extern C methods.

No. The COM classes are proper C++ classes with proper v-tables. What the macros do is to describe equivalent structs so that COM interfaces can be used through straight C. Why you''d want to, I don''t know.

Share this post


Link to post
Share on other sites
quote:
Original post by DrPizza
No it doesn''t. COM exists on a variety of platforms, including most UNIXes.



Oh. I''m quite unaware of that. But if one can generate the proper macros/tools for the compiler, I''m pretty sure there''s no reason why it can''t be done. After all, the implementation doesn''t need use any platform specific libraries.

quote:
The COM headers have macros that either construct a v-table with proper v-table lookups (for use with C++), or a set of structs that match the v-table (for use with C). They don''t bypass the v-table.



Bypass is a wrong word to use. What I meant was the macros implements a vtable type lookup table in C style, which is normally done behind the scene in the C++ compiler.

quote:
No. The COM classes are proper C++ classes with proper v-tables. What the macros do is to describe equivalent structs so that COM interfaces can be used through straight C. Why you''d want to, I don''t know.


That''s the only way you can get platform/compiler independence - by specifying vtable layout and avoid C++ name mangling = C way.

If you don''t think that''s ugly, frankly I don''t know what is.

Share this post


Link to post
Share on other sites
quote:
Original post by Void
That''s the only way you can get platform/compiler independence - by specifying vtable layout and avoid C++ name mangling = C way.



As long as you''re using MSVC++, you don''t need those macros at all. They''re there so you can access COM from C, or from a non-Microsoft compiler (COM''s vtable is exactly the same as Microsoft''s compiler''s C++ vtable).

Don''t forget that COM is not only meant for C++, but also from VB, Pascal, Cobol, and basically any other language you can think of.

If I had my way, I''d have all of you shot!


codeka.com - Just click it.

Share this post


Link to post
Share on other sites