I'm trying to modify a clone class so that it can compile in VC++ 6.0
and Borland BCC55 compilers.
The original class is in the following link:
http://code.axter.com/copy_ptr_original.h
The above version compiles in VC++ 7.1 and GNU 3.x compilers, but it
does not compile in VC++ 6.0, nor does it compile in Borland BCC55.
I modified to the code to the following:
http://code.axter.com/copy_ptr.h
This version does compile in all 4 compilers, but I'm concern that it
may not be portable because it's mixing function types.
typedef T * ( *clone_fct_Type ) ( T *, bool, void* = NULL, void* =
NULL);
clone_fct_Type m_clone_fct;
.......
.......
copy_ptr(T_obj* type):m_type(type), m_clone_fct(NULL)
{
T * ( *tmp ) ( T *, bool, T_obj* = NULL, std::allocator<T_obj>* =
NULL) = ConstructAndDestruct<T,T_obj, std::allocator<T_obj> >;
m_clone_fct = (clone_fct_Type)tmp;
}
Is the above workaround method portable?
Can any one think of a more elegant method that is equally or more
efficient?
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
0
|
|
|
|
Reply
|
temp (103)
|
9/9/2005 3:26:38 PM |
|
axter wrote:
> I'm trying to modify a clone class so that it can compile in VC++ 6.0
> and Borland BCC55 compilers.
> The original class is in the following link:
> http://code.axter.com/copy_ptr_original.h
>
> The above version compiles in VC++ 7.1 and GNU 3.x compilers, but it
> does not compile in VC++ 6.0, nor does it compile in Borland BCC55.
> I modified to the code to the following:
>
> http://code.axter.com/copy_ptr.h
>
> This version does compile in all 4 compilers, but I'm concern that it
> may not be portable because it's mixing function types.
It's not even mixing them, it is using brute force (casting) to invoke
undefined behaviour.
> typedef T * ( *clone_fct_Type ) ( T *, bool, void* = NULL, void* =
> NULL);
> clone_fct_Type m_clone_fct;
> ......
> ......
> copy_ptr(T_obj* type):m_type(type), m_clone_fct(NULL)
> {
> T * ( *tmp ) ( T *, bool, T_obj* = NULL,
> std::allocator<T_obj>* = NULL) =
> ConstructAndDestruct<T,T_obj, std::allocator<T_obj> >;
> m_clone_fct = (clone_fct_Type)tmp;
Brute force cast here.
> Can any one think of a more elegant method that is equally or more
> efficient?
You are discarding type information by passing void*. The only 'proper' way
to get them back is to use static_cast (of course, you need to KNOW that
it's save!) on a pointer, but it's not save/portable to do this with a
function pointer. Note: there is no way in C or C++ to cast a function
pointer without invoking UB, but POSIX and its dlopen/dlsym require that,
but of course you have to make sure that the types match the original,
which is not given in your case.
So, what you can do is create a template function (possibly class-static)
that takes typeless parameters plus a function pointer, gives the
parameters their type back (with static_cast) and then calls the function.
One thing which will further spoil your fun is the fact that the
ConstructAndDestruct function only has the last two parameters because the
name-mangling in MSC<13 (i.e. the compiler of VC6 but also eVC4)
disregards template parameters and only considers function parameters.
That means that without those (otherwise unused) default parameters
different instantiations will generate the same linker symbol and thus
lead to runtime errors.[1]
Without that, you could just drop these two dummy parameters and have all
clone functions have the same type.
Other than that, you could instead use a class for MSC12, as with classes
the name-mangling works sufficiently:
template<typename BaseType, typename DerivedType, typename AllocatorType>
struct Helper
{
static BaseType* ConstructAndDestruct( BaseType* ptr, bool bConstruct)
{ ... }
};
A totally different approach (though I think it doesn't work too well with
class hierarchies) is to use Boost.Any, which has an elaborated cloning
helper.
Uli
[1] You obviously knew that already. So much for the golden rule of
documenting workarounds in code....
--
Questions ?
see C++-FAQ Lite: http://parashift.com/c++-faq-lite/ first !
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
0
|
|
|
|
Reply
|
Ulrich
|
9/10/2005 1:39:56 PM
|
|
Ulrich Eckhardt wrote:
> axter wrote:
> > I'm trying to modify a clone class so that it can compile in VC++ 6.0
> > and Borland BCC55 compilers.
> > The original class is in the following link:
> > http://code.axter.com/copy_ptr_original.h
> >
> > The above version compiles in VC++ 7.1 and GNU 3.x compilers, but it
> > does not compile in VC++ 6.0, nor does it compile in Borland BCC55.
> > I modified to the code to the following:
> >
> > http://code.axter.com/copy_ptr.h
> >
> > This version does compile in all 4 compilers, but I'm concern that it
> > may not be portable because it's mixing function types.
>
> It's not even mixing them, it is using brute force (casting) to invoke
> undefined behaviour.
Please give details as to what is undefined behaviour, and IAW what
part of the C++ standard.
>
> > typedef T * ( *clone_fct_Type ) ( T *, bool, void* = NULL, void* =
> > NULL);
> > clone_fct_Type m_clone_fct;
> > ......
> > ......
> > copy_ptr(T_obj* type):m_type(type), m_clone_fct(NULL)
> > {
> > T * ( *tmp ) ( T *, bool, T_obj* = NULL,
> > std::allocator<T_obj>* = NULL) =
> > ConstructAndDestruct<T,T_obj, std::allocator<T_obj> >;
> > m_clone_fct = (clone_fct_Type)tmp;
>
> Brute force cast here.
>
> > Can any one think of a more elegant method that is equally or more
> > efficient?
>
> You are discarding type information by passing void*. The only 'proper' way
> to get them back is to use static_cast (of course, you need to KNOW that
> it's save!) on a pointer, but it's not save/portable to do this with a
> function pointer. Note: there is no way in C or C++ to cast a function
> pointer without invoking UB, but POSIX and its dlopen/dlsym require that,
> but of course you have to make sure that the types match the original,
> which is not given in your case.
If you would have looked at the original code, you would have seen that
these extra arguments are not needed.
The original and the new code don't use the last two arguments.
They're only there so as to allow the two non-compliant compilers to
compile the code.
> So, what you can do is create a template function (possibly class-static)
> that takes typeless parameters plus a function pointer, gives the
> parameters their type back (with static_cast) and then calls the function.
>
> One thing which will further spoil your fun is the fact that the
> ConstructAndDestruct function only has the last two parameters because the
> name-mangling in MSC<13 (i.e. the compiler of VC6 but also eVC4)
> disregards template parameters and only considers function parameters.
> That means that without those (otherwise unused) default parameters
> different instantiations will generate the same linker symbol and thus
> lead to runtime errors.[1]
> Without that, you could just drop these two dummy parameters and have all
> clone functions have the same type.
>
> Other than that, you could instead use a class for MSC12, as with classes
> the name-mangling works sufficiently:
>
> template<typename BaseType, typename DerivedType, typename AllocatorType>
> struct Helper
> {
> static BaseType* ConstructAndDestruct( BaseType* ptr, bool bConstruct)
> { ... }
> };
>
> A totally different approach (though I think it doesn't work too well with
> class hierarchies) is to use Boost.Any, which has an elaborated cloning
> helper.
I have a similar method as the above Helper object in the following
code:
http://code.axter.com/clone_ptr.h
Although this method is portable (and works with VC++ 6.0 & BCC55), it
uses a virtual object that has to be created and destroyed for each
instance of the smart pointer.
The helper object method is not as efficient as the function pointer
method.
> Uli
>
> [1] You obviously knew that already. So much for the golden rule of
> documenting workarounds in code....
That's why I posted a link to both original and new code, so that
anyone can easily make the comparison.
I haven't documented it since this workaround is not firm yet, because
I'm not sure if it's portable IAW C++ standard.
So my main question still remains. Is my function pointer workaround
method portable.
If not portable, can someone please give details with reference to the
C++ standard.
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
0
|
|
|
|
Reply
|
axter
|
9/11/2005 3:12:44 PM
|
|
|
2 Replies
226 Views
(page loaded in 0.132 seconds)
|