C++: C with Crashes...

This is a discussion on C++: C with Crashes... within the C++ Programming forums, part of the General Programming Boards category; Today I am going to tell you about a potentially unforseen feature of the C++ language (or rather the compiler's ...

  1. #1
    Guest Sebastiani's Avatar
    Join Date
    Aug 2001
    Location
    Waterloo, Texas
    Posts
    5,600

    Post C++: C with Crashes...

    Today I am going to tell you about a potentially unforseen feature of the C++ language (or rather the compiler's interpretation of the language) that makes using callbacks not just difficult (you already knew that!), but deadly. Let me explain:

    Assume you have a base class called cBase, with a derived class cDerived. The base class defines a linked list of cBase:: callbacks, and also a plethora of methods for manipulating the list.

    Now cDerived defines a new function with a signature compatible with the list, and with a little static_cast<> prodding, pushes the function into it. At some later time, the list is traversed, and the functions are invoked. Crash! What the hell happened, you say?

    The culprit was in derefrencing (both implicitly and explicitly) the "this" pointer(!) on cDerived's members within the functions. Even though the functions were declared within the class using them, because of the cast, they are rendered virtually useless! You simply cannot make it work! Wow, that sucks, you say. Oh, but that's not all!!

    So being the clever shmuck that you are, you decide to give cBase a new member, a void * pointer named "work_around", and cDerived a pointer to a cDerived named "This". You pass "this" into the cBase function that swallows callbacks, and point "work_around" to it. Later, in cDerived's constructor, you cast "work_around" into a cDerived and assign it to "This". The functions themselves internally use "This->", not "this->"... sounds bulletproof, right?

    Well, unless there is some flaw in my logic here(or even my compiler), no. The results were identical. The moral of the story is that C++ is not perfect, and can be quite a pain at times. Having said that, I cannot see myself parting with it any time soon, but -to be sure - whatever ugly hack I must come up with to work around this obnoxious problem will always serve as solemn reminder to me that SOMEDAY...I MUST WRITE MY OWN COMPILER!!!

    You have been forewarned!
    Last edited by Sebastiani; 10-26-2002 at 11:05 PM.
    Code:
    if( numeric_limits< byte >::digits != bits_per_byte )
        error( "program requires bits_per_byte-bit bytes" );
    24bbs.cpp

  2. #2
    Skunkmeister Stoned_Coder's Avatar
    Join Date
    Aug 2001
    Posts
    2,572
    What are you trying to do seba?
    could you illustrate it with a code sample?
    Free the weed!! Class B to class C is not good enough!!
    And the FAQ is here :- http://faq.cprogramming.com/cgi-bin/smartfaq.cgi

  3. #3
    geek SilentStrike's Avatar
    Join Date
    Aug 2001
    Location
    NJ
    Posts
    1,141
    How about deriving from cBase (with a member function called doIt(), or something more applicable) for as many different functions you want to have called back. Instead of keeping a list of pointer to cBase functions in cBase, keep a list of cBase*. Each time you want to call something from cBase, simply call the doIt member of whatever is in the list. You get the same not determined til runtime what function will be called, except no crashes.
    Prove you can code in C++ or C# at TopCoder, referrer rrenaud
    Read my livejournal

  4. #4
    Guest Sebastiani's Avatar
    Join Date
    Aug 2001
    Location
    Waterloo, Texas
    Posts
    5,600
    This specifically relates to creating a mechanism that makes the standard WindowProcedure an invisible, unchanging entity. Instead, derived classes simply "announce" the message they're interested in and tie it to a Windows message. Message mapping.

    Here's an example I posted to another thread. The program is "complete", and runs as is:

    Code:
    class button : public Button {
    public:
    
    button(int w, int h) {
     SetWidthHeight(w, h);
     Register(&button::Hello, WM_LBUTTONDOWN); //..."the map"..
    }
    
    void Hello() {
     Alert("Stop clicking me!!!");
    }
    };
    
    button b(100, 25);
    
    int WINAPI WinMain(/**/){
     
     win.Create(); //..use defaults, for clarity.
     
     b.Create(&win);
    
     return win.RunMessageLoop();
    }
    Code:
    if( numeric_limits< byte >::digits != bits_per_byte )
        error( "program requires bits_per_byte-bit bytes" );
    24bbs.cpp

  5. #5
    Guest Sebastiani's Avatar
    Join Date
    Aug 2001
    Location
    Waterloo, Texas
    Posts
    5,600
    Well, the whole idea is not having to predetermine anything in your implementation. Classes simply define their own functions, and register them. Before, I did similar to what you're saying, except I defined virtual functions, OnLeftButtonDown(), and so forth. But whenever I thought of a new handler, I had to add code to my library. Thus the need for change...
    Code:
    if( numeric_limits< byte >::digits != bits_per_byte )
        error( "program requires bits_per_byte-bit bytes" );
    24bbs.cpp

  6. #6
    geek SilentStrike's Avatar
    Join Date
    Aug 2001
    Location
    NJ
    Posts
    1,141
    In that case, I can see my solution really wouldn't work. You could instead have a virtual onLButtonDown member of the base class, which is called by whatever is handling the messages on your subclass of button.

    Code:
    class button : public Button {
    public:
    
    button(int w, int h) {
     SetWidthHeight(w, h);
    }
    
    void onLButtonDown() {
     Alert("Stop clicking me!!!");
    }
    };
    Prove you can code in C++ or C# at TopCoder, referrer rrenaud
    Read my livejournal

  7. #7
    geek SilentStrike's Avatar
    Join Date
    Aug 2001
    Location
    NJ
    Posts
    1,141
    Heh... posted that right before I read your response.

    What do you mean that you need to change your library everytime you add a new handler? Shouldn't the handler itself just be relaying messages to the other objects?
    Last edited by SilentStrike; 10-26-2002 at 11:02 PM.
    Prove you can code in C++ or C# at TopCoder, referrer rrenaud
    Read my livejournal

  8. #8
    Guest Sebastiani's Avatar
    Join Date
    Aug 2001
    Location
    Waterloo, Texas
    Posts
    5,600
    Reads fine if you start from the bottom of the thread
    Code:
    if( numeric_limits< byte >::digits != bits_per_byte )
        error( "program requires bits_per_byte-bit bytes" );
    24bbs.cpp

  9. #9
    Skunkmeister Stoned_Coder's Avatar
    Join Date
    Aug 2001
    Posts
    2,572
    read this
    Free the weed!! Class B to class C is not good enough!!
    And the FAQ is here :- http://faq.cprogramming.com/cgi-bin/smartfaq.cgi

  10. #10
    Skunkmeister Stoned_Coder's Avatar
    Join Date
    Aug 2001
    Posts
    2,572
    sorry crappy php link not working. go to that site and look for this tutorial....

    Creating a Win32 Window Wrapper Class
    by Oluseyi Sonaiya
    Free the weed!! Class B to class C is not good enough!!
    And the FAQ is here :- http://faq.cprogramming.com/cgi-bin/smartfaq.cgi

  11. #11
    S Sang-drax's Avatar
    Join Date
    May 2002
    Location
    Göteborg, Sweden
    Posts
    2,072
    This works for me.
    Code:
    #include <iostream>
    
    class Base
    {
     public:
        //Runs the function stored in the pointer
        void ExecuteFunction();  
     protected:
        typedef void (Base::*base_func_ptr)(int);
        template<class T>
            void Connect(void (T::*func)(int))
            {
                func_ptr = static_cast<base_func_ptr>(func);
            }
        base_func_ptr func_ptr;      
    };
    
    void Base::ExecuteFunction()
    {
        (this->*func_ptr)(15);
    }
    
        
    
    class Derived:
        public Base
    {
     public:
            
        //Member function to be added to Base
        void Test(int i)
        {
            //Output a simple multiplication, using a member
            //variable and the argument
            std::cout << member*i;
        }
        
        Derived():
            member(3) 
        {
            Connect(Test);
        }
            
        int member;
    };
    
    
    int main()
    {
        Derived d;
        d.ExecuteFunction();
        std::cin.ignore(1000,'\n');
    }
    (edit) Now using template (/edit)
    (edit2) Now works in VC++.NET (/edit2)
    Last edited by Sang-drax; 10-27-2002 at 09:23 AM.
    Last edited by Sang-drax : Tomorrow at 02:21 AM. Reason: Time travelling

  12. #12
    Guest Sebastiani's Avatar
    Join Date
    Aug 2001
    Location
    Waterloo, Texas
    Posts
    5,600
    Unfortunately, it still crashes =(
    Code:
    if( numeric_limits< byte >::digits != bits_per_byte )
        error( "program requires bits_per_byte-bit bytes" );
    24bbs.cpp

  13. #13
    S Sang-drax's Avatar
    Join Date
    May 2002
    Location
    Göteborg, Sweden
    Posts
    2,072
    What compiler are you using?

    My code works in CodeWarrior.

    (Edit: also works in VC++.NET )
    Last edited by Sang-drax; 10-27-2002 at 09:23 AM.
    Last edited by Sang-drax : Tomorrow at 02:21 AM. Reason: Time travelling

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Random crashes? huh?
    By cpjust in forum C++ Programming
    Replies: 28
    Last Post: 07-09-2008, 08:41 PM
  2. Loop crashes
    By mrtilley in forum C Programming
    Replies: 8
    Last Post: 10-19-2007, 07:30 AM
  3. Program crashes and memory leaks
    By ulillillia in forum Tech Board
    Replies: 1
    Last Post: 05-15-2007, 10:54 PM
  4. DEV-C++ made program crashes when run from outside the ide
    By rainmanddw in forum C++ Programming
    Replies: 3
    Last Post: 01-20-2006, 09:27 PM
  5. Program crashes and I can't figure out why
    By Unregistered in forum C Programming
    Replies: 6
    Last Post: 09-19-2001, 05:33 PM

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21