Re: Passing pointers across implementation boundaries
On 15/02/10 04:55, Paul Bibbings wrote:
Specifically, I'm thinking here about passing pointers to standard
library objects across implementation boundaries (and, indeed, across
DLL boundaries).
Let us say that we have a shared library, implemented in MSVC, that
exposes the following interface (pseudocode):
// shared_lib_export.h
extern "C" {
__declspec(dllexport) std::ostream* __cdecl
GetNewStream(); // dynamically allocated
__declspec(dllexport) void __cdecl
PrintToStream(std::ostream*, const char *);
__declspec(dllexport) void __cdecl
FreeStream(std::ostream*); // deallocated
}
What extern "C" does is that it turns off C++ name mangling because the
mangling is different across different C++ compilers.
If the compiler that includes this header file has a different mangling
it is highly likely that it has incompatible C++ binary API and/or
incompatible standard C++ library. Putting a C++ API into extern "C"
turns off this safety net for no reason.
Then, in an application built using another implementation, say GNU gcc,
suppose I want to do something like:
#include<ostream>
#include "shared_lib_import.h"
int main()
{
std::ostream* os = GetNewStream();
PrintToStream(os, "Is this valid/safe/insane?\n");
FreeStream(os);
return 0;
}
What can we say about the validity of obtaining, storing and passing
back for use a pointer in this way?
It won't work because MSVC and gcc have different standard libraries.
MSVC std::ostream has one declaration, gcc std::ostream has another and
they are not compatible.
It will work with the same C++ compiler though.
Can this ever be well-defined, and
what are the minimal guarantees that we must require for it to be so
(not to mention passing across the C-style string)?
Only if the compilers in question agree on the C++ binary API, as Linux
versions of gcc and Intel do.
For instance, I'm guessing that the size of a pointer in both
implementations would need to be the same.
Pointer sizes are most often defined by platform C binary API, so that
all compilers for that platform must obey it (otherwise they won't be
able to call platform/kernel functions that accept pointers).
Also, we have to allow the
shared library code to manage the destruction of the object pointed to,
ensuring its valid lifetime by a properly-balanced use of GetNewStream()
and FreeStream(...). More importantly, we would have to forget about
any attempts to use the object in our calling code, in the sense of
dereferencing the pointer.
In short, can such a use ever be viable, and if so, under what
circumstances?
Not in C++. You would need to wrap your API in C to make it truly portable.
--
Max
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]