Thread: Staticly Bound Member Function Pointers

  1. #1
    Programming Sex-God Polymorphic OOP's Avatar
    Join Date
    Nov 2002
    Posts
    1,078

    Thumbs down Staticly Bound Member Function Pointers

    I've been thinking lately and I have to say I'm a little bit mad with the standard concerning member function pointers. Since the standard accounts for both virtual and nonvirtual member function pointers as being the same type and forces dynamic binding on virtual functions, one of two possibilities comes to mind in terms of how the compiler would handle such a "problem":

    Either the compiler's version of member function pointers has to store two values -- a vtable offset/pointer union (assuming they are using a vtable for polymorphism), and a value representing whether the function is virtual or nonvirtual (which wouldn't be very efficient in terms of memory use and forces a check whenever it's dereferenced), or the compiler creates a table for nonvirtual function pointers as well as for virtual, just for the sake of member function pointers, so that they can be accessed and stored in the same way as virtual member functions. The function pointer table could be stored "behind" the start of the vtable (sort of like how data is usually stored "behind" a dynamically allocated array for the purpose of deallocation).

    But that brings me to my point. If the latter is true, then that means that when you use a member function pointer to call a nonvirtual member function, it is forcibly dynamically bound! I know it's not something that's extremely taxing, but it is taxing none-the-less. I checked sizeof( void(a::*)() ) on msvc++ 6.0 and it is returning 4, which in this case is the exact same amount of bytes needed for a pointer to a "regular" datatype (IE int, float, void), so unless they are doing something that I'm not thinking of, then they are forcing dynamic binding on functions where it is not necissary. I've never exactly made a compiler, so I can't say I've given this an extreme amount of thought, but as of now, I don't see any other way to do this without having to use more than sizeod(void*) for the data.

    I'm not saying I disagree with msvc++, as theirs is the best approach that I can think of, but what I am saying is that I think the standard needs a minor adjustment. Perhaps I'm being a bit too concerned, but there is a solution I've come up with that I don't see any problems with:


    --------------------

    2 datatypes for member function pointers:

    a datatype for both virtual and nonvirtual member functions (this is the standard implementation as it is now, and still is obviously necissary)

    AND

    a datatype that forces static binding on member functions (IE, a syntactical variant on standard function pointers)

    --------------------


    The purpose of this is both speed and memory occupancy. Why account for dynamic binding where you have no virtual functions or specifically want to force static binding of a parent version of the class rather than the child version? If you comply to the standard, then the latter isn't even possible!!!

    It just doesn't make sense to me why they wouldn't account for such possibilities. Member function pointers are not used extremely often, but they still are used. I've come into a situation where the former problem exists and it angred me to find out there was no way of handling it. I'm sure I'm not the only one who has come accross this limitation of the language. I just don't understand why they thought such functionality wouldn't be useful.

    Any insight?

  2. #2
    Banned master5001's Avatar
    Join Date
    Aug 2001
    Location
    Visalia, CA, USA
    Posts
    3,685
    Hmmm...This isn't really a question per se so I guess I can just add my two cents. First off all pointers are the same size

    Code:
    sizeof(int(*)(void *, void *, int, int, int)) == sizeof(int *)
    Although you do bring up some interesting points I have found that the longer you program the more little issues like this come up in practice (not just speculation). And the more of that these little issues come up the more you find yourself understanding why the standard is written as it is.

  3. #3
    S Sang-drax's Avatar
    Join Date
    May 2002
    Location
    Göteborg, Sweden
    Posts
    2,072
    Originally posted by master5001
    First off all pointers are the same size
    Wrong.

    Code:
    class a;
    cout << sizeof( void (a::*)() ) << endl;
    cout << sizeof( void * ) << endl;
    Complie this in CodeWarrior and you get the following output:
    Code:
    12
    4
    Last edited by Sang-drax : Tomorrow at 02:21 AM. Reason: Time travelling

  4. #4
    &TH of undefined behavior Fordy's Avatar
    Join Date
    Aug 2001
    Posts
    5,793
    >>Complie this in CodeWarrior and you get the following output:

    My guess is that this is sizeof() doing more work than you are asking....I think its saying that that function pointer uses 3 pointers to operate....not that that pointer itself takes up 12 bytes.....

  5. #5
    S Sang-drax's Avatar
    Join Date
    May 2002
    Location
    Göteborg, Sweden
    Posts
    2,072
    If so, it all depends on how you define pointer.

    If it's just a memory address, then, yes, the function pointer is probably three pointers

    (and it is)

    But fact remains, the (pointer to a member function) is 12 bytes long.
    Last edited by Sang-drax : Tomorrow at 02:21 AM. Reason: Time travelling

  6. #6
    &TH of undefined behavior Fordy's Avatar
    Join Date
    Aug 2001
    Posts
    5,793
    Originally posted by Sang-drax
    If so, it all depends on how you define pointer.

    If it's just a memory address, then, yes, the function pointer is probably three pointers

    (and it is)

    But fact remains, the (pointer to a member function) is 12 bytes long.
    Curiously, a member func pointer has a sizeof of 4 for VC++6!!!

    And 8 under Mingw!!!!

  7. #7
    Programming Sex-God Polymorphic OOP's Avatar
    Join Date
    Nov 2002
    Posts
    1,078
    Originally posted by master5001
    First off all pointers are the same size
    Actually, you are wrong there. C++ makes the specific exception for member function pointers because they have to account for polymorphism, which cannot be done by a single pointer.

    In terms of the codewarrior example, sizeof was NOT doing something extra. The member function "pointer" actually does take up that amount of space for the compiler. The standard is very lax on member function pointer implementation and so it is perfectly fine. They just chose not to create member function pointers in the same way the mscv++ 6.0 does it.

  8. #8
    Guest Sebastiani's Avatar
    Join Date
    Aug 2001
    Location
    Waterloo, Texas
    Posts
    5,708
    That's pretty ridiculous. Why would they set it up like that? Surely they were concerned about speed? There must be some other reason then.
    Code:
    #include <cmath>
    #include <complex>
    bool euler_flip(bool value)
    {
        return std::pow
        (
            std::complex<float>(std::exp(1.0)), 
            std::complex<float>(0, 1) 
            * std::complex<float>(std::atan(1.0)
            *(1 << (value + 2)))
        ).real() < 0;
    }

  9. #9
    Programming Sex-God Polymorphic OOP's Avatar
    Join Date
    Nov 2002
    Posts
    1,078
    If you're refering to why member function pointers are not "pointers" in the regular sense of the word, it's because of virtual functions. In fact, that makes it slower.

    If you mean why does code warrior have 3 times more space needed for member function "pointers" than msvc++, then speed is the only thing I can think of, but I doubt that the speed difference is significant enough to account for making the data required 3 times larger.

  10. #10
    &TH of undefined behavior Fordy's Avatar
    Join Date
    Aug 2001
    Posts
    5,793
    Originally posted by Sebastiani
    That's pretty ridiculous. Why would they set it up like that? Surely they were concerned about speed? There must be some other reason then.
    I would just like to state that although my codewarrior's sizeof() returned 12, it produced the same assembler for the actual call as VC++ (loading the stack address of the object into a register and then issuing the call)...just a matter of interpretation I guess

  11. #11
    Guest Sebastiani's Avatar
    Join Date
    Aug 2001
    Location
    Waterloo, Texas
    Posts
    5,708
    Interesting. Actually, I was confused. I thought the poster was implying that ALL compilers forced dynamic binding on pfn's to non-virtual members. But having reread it, I see it's optional. Luckily for me, my compiler uses 12 bytes per pfn.
    Code:
    #include <cmath>
    #include <complex>
    bool euler_flip(bool value)
    {
        return std::pow
        (
            std::complex<float>(std::exp(1.0)), 
            std::complex<float>(0, 1) 
            * std::complex<float>(std::atan(1.0)
            *(1 << (value + 2)))
        ).real() < 0;
    }

  12. #12
    Programming Sex-God Polymorphic OOP's Avatar
    Join Date
    Nov 2002
    Posts
    1,078
    That's just an opinion. Personally, I'd much rather have just 4 bytes in memory rather than 12, even if it means forced dynamic binding, especially considering there are still going to be some checks that have to be made in the 12 byte version to check if the function is virtual or not.

    Anyways, this is the reason I posted. Both situations can happen, but often times you only need a literal member function pointer (like a function pointer). That would resolve any issues and give more control to the programmer on a separate level from the way the compiler is implemented.

  13. #13
    Guest Sebastiani's Avatar
    Join Date
    Aug 2001
    Location
    Waterloo, Texas
    Posts
    5,708
    Trade speed for size? No way. Just how many pfn's could you have anyway? Even 1000 would add a mere 8K to your exe.
    Code:
    #include <cmath>
    #include <complex>
    bool euler_flip(bool value)
    {
        return std::pow
        (
            std::complex<float>(std::exp(1.0)), 
            std::complex<float>(0, 1) 
            * std::complex<float>(std::atan(1.0)
            *(1 << (value + 2)))
        ).real() < 0;
    }

  14. #14
    Programming Sex-God Polymorphic OOP's Avatar
    Join Date
    Nov 2002
    Posts
    1,078
    It depends on what you're optimizing for. Speed isn't always what you're trying to optimize. And it's not a simple matter of speed vs space. It's an unbelievably small (almost not noticeable) amount of speed, vs 3 times the amount of space. You can say that 12 bytes isn't a lot, but it's the ratio that matters!

  15. #15
    Guest Sebastiani's Avatar
    Join Date
    Aug 2001
    Location
    Waterloo, Texas
    Posts
    5,708
    Yes well I would argue that dynamic is probably ~1/3 as fast as static bound pfn's. That could really hurt a loop brother.
    Code:
    #include <cmath>
    #include <complex>
    bool euler_flip(bool value)
    {
        return std::pow
        (
            std::complex<float>(std::exp(1.0)), 
            std::complex<float>(0, 1) 
            * std::complex<float>(std::atan(1.0)
            *(1 << (value + 2)))
        ).real() < 0;
    }

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Undefined Reference Compiling Error
    By AlakaAlaki in forum C++ Programming
    Replies: 1
    Last Post: 06-27-2008, 11:45 AM
  2. We Got _DEBUG Errors
    By Tonto in forum Windows Programming
    Replies: 5
    Last Post: 12-22-2006, 05:45 PM
  3. Including lib in a lib
    By bibiteinfo in forum C++ Programming
    Replies: 0
    Last Post: 02-07-2006, 02:28 PM
  4. Problem with Visual C++ Object-Oriented Programming Book.
    By GameGenie in forum C++ Programming
    Replies: 9
    Last Post: 08-29-2005, 11:21 PM
  5. Replies: 4
    Last Post: 11-23-2003, 07:15 AM