c++ brutal cast = safe?

Started by
18 comments, last by Schrompf 14 years, 10 months ago
Consider the following scenario: class myClass {... void method(); }; typedef void (*proc)(void *); ... myClass object; void *ptr = &object// cast object to void * proc foo = &myClass::method; // cast class method to type 'proc' (brutal) and now if i do 'foo(ptr);' the 'method' from 'object' will be called. this is equivalent with object.method(); In visual studio 2008 this is allowed and it works with no problems as far as i tested this.Is this absolutely safe with any class type and on other compilers? Thanks Raxvan.
Advertisement
Quote:Original post by Makaan
In visual studio 2008 this is allowed and it works with no problems as far as i tested this.Is this absolutely safe with any class type and on other compilers?
That it works at all is a small miracle, and purely an implementation artefact. This behaviour is neither standard, nor portable, and there are probably many situations where it won't work even under your compiler.

If you actually want to do something like this, you can use member function pointers, or better yet, std::mem_fun or boost::bind.

Tristam MacDonald. Ex-BigTech Software Engineer. Future farmer. [https://trist.am]

Quote:Original post by Makaan
Consider the following scenario:

class myClass {... void method(); };

typedef void (*proc)(void *);
...

myClass object;
void *ptr = &object// cast object to void *
proc foo = &myClass::method; // cast class method to type 'proc' (brutal)

The line proc foo = &myClass::method shouldn't compile. You are missing a (proc*) in the above line?

In any case, yes, the fact that it works is a complete accident and implementation detail of your particular compiler.

An easy way around this is:
class myClass {  // ...  void method();  static void method_func( myClass* self ) { self->method(); }  // ...};myClass object;void* ptr = &object; // implicitly get a void pointer to object.proc foo = myClass::method_func; // these are type-compatible... probably

As mentioned in the above link, calling conventions _could_ vary between a static member function and a raw C interface that you might end up passing proc to.
Quote:Original post by swiftcoder
Quote:Original post by Makaan
In visual studio 2008 this is allowed and it works with no problems as far as i tested this.Is this absolutely safe with any class type and on other compilers?
That it works at all is a small miracle, and purely an implementation artefact. This behaviour is neither standard, nor portable, and there are probably many situations where it won't work even under your compiler.

If you actually want to do something like this, you can use member function pointers, or better yet, std::mem_fun or boost::bind.


thanks for the links, i will try to rethink my design.

It it not a miracle at all the fact that this works, because as far as i know for any c++ implementation uses the same design for OOP(i don't know if there are any exceptions). Any class method is actualy a normal function that has the first argument a pointer to the object (the hidden 'this' keyword) . I can't think of a problem if i manually pass that pointer into the stack and the call the method, the function will simply get fooled.


Edit:
NotAYakk you are right the line proc foo = &myClass::method; will not compile ,
it is just to represent my idea, i fount a way to force the compiler to make that brutal casting.

The static method is iteresting. thanks
class Foo {public:  virtual void method() = 0;};class Bar {public:  virtual void method() {}};class Baz: public Bar, public Foo {public:  virtual void method() { printf("Baz!\n"); }};typedef void(Foo::*FooMethod)();typedef void(Bar::*BarMethod)();typedef void(Baz::*BazMethod)();int main(int, char**) {  printf("%d %d %d == %d?\n", (int)sizeof(FooMethod), (int)sizeof(BarMethod), (int)sizeof(BazMethod), sizeof(void*));  return 0;}

What does the above print out on your system? (not compiled, just tossed out there).

IIRC, not all methods pointers sizeof(void*), even on relatively standard compilers.
Quote:Original post by Makaan
It it not a miracle at all the fact that this works, because as far as i know for any c++ implementation uses the same design for OOP(i don't know if there are any exceptions). Any class method is actualy a normal function that has the first argument a pointer to the object (the hidden 'this' keyword) . I can't think of a problem if i manually pass that pointer into the stack and the call the method, the function will simply get fooled.
Except for the fact that that isn't guaranteed to work on any compiler. You're relying on implementation details which you have no control over and, quite frankly, know nothing about (as they might vary from system to system). Hacking your code up so that it relies on such implementation details is not standard, is not defined, and is not safe.
[size=2][ I was ninja'd 71 times before I stopped counting a long time ago ] [ f.k.a. MikeTacular ] [ My Blog ] [ SWFer: Gaplessly looped MP3s in your Flash games ]
> Any class method is actualy a normal function that has the first
> argument a pointer to the object (the hidden 'this' keyword) .
There are actually two problems with that:
1. depending on the compiler/ABI, member function pointer can be represented differently in memory; member function pointers can be as large as 16 bytes on some compilers.
2. depending on the compiler/ABI, calling convention for regular and member functions may differ; for example, MSVC defaults to thiscall for member functions (this is passed in ecx register, arguments are passed via stack).
damn, 4 4 8 = 4 , nice to know , so my code is not safe :).
Quote:Original post by Makaan
NotAYakk you are right the line proc foo = &myClass::method; will not compile ,
it is just to represent my idea, i fount a way to force the compiler to make that brutal casting.

How did you get that to compile? MSVC seems to reject all the obvious approaches.
Quote:Original post by SiCrane
Quote:Original post by Makaan
NotAYakk you are right the line proc foo = &myClass::method; will not compile ,
it is just to represent my idea, i fount a way to force the compiler to make that brutal casting.

How did you get that to compile? MSVC seems to reject all the obvious approaches.


typedef void (*SimpleProc)(void *);

template< class T >
Callback(T * MyObject,void (T:: *proc)())
{
obj= (void *)MyObject;

void (T:: *aux)() = proc;
void * adr = ((void *)&aux);
foo = *((SimpleProc *)adr); //uber brutal cast
}
and voila , 'foo(obj)' :)

This topic is closed to new replies.

Advertisement