Thread: Staticly Bound Member Function Pointers

  1. #16
    &TH of undefined behavior Fordy's Avatar
    Join Date
    Aug 2001
    Posts
    5,793
    Originally posted by Polymorphic OOP
    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!
    As I said, in my 2 examples with the most varying results for sizeof on a member function pointer (VC++6 - 4, Codewarrior 5 - 12), both compilers produced the same code to call the function.....they both loaded the address for the object into a register and then issued the call - same amount of code upto the actual function declarations!

    Also both cases were in debug mode without any real optimisation...

    Personally I wouldnt get too hung up on the sizeof returned from these function pointers.........

  2. #17
    ¡Amo fútbol!
    Join Date
    Dec 2001
    Posts
    2,138
    Polymorphic OOP
    Junior Member

    Registered: Nov 2002
    Location: Redmond, WA
    Posts: 6
    Me is thinking something...

  3. #18
    Programming Sex-God Polymorphic OOP's Avatar
    Join Date
    Nov 2002
    Posts
    1,078
    Originally posted by golfinguy4
    Me is thinking something...
    Hmm?

  4. #19
    ¡Amo fútbol!
    Join Date
    Dec 2001
    Posts
    2,138
    Redmond, Washington... home of ________

    I read your profile though so it seems I am wrong.

  5. #20
    Programming Sex-God Polymorphic OOP's Avatar
    Join Date
    Nov 2002
    Posts
    1,078
    Originally posted by Fordy
    As I said, in my 2 examples with the most varying results for sizeof on a member function pointer (VC++6 - 4, Codewarrior 5 - 12), both compilers produced the same code to call the function.....they both loaded the address for the object into a register and then issued the call - same amount of code upto the actual function declarations!

    Also both cases were in debug mode without any real optimisation...

    Personally I wouldnt get too hung up on the sizeof returned from these function pointers.........
    By the way you're describing it this sounds as though you are saying that member function pointers are just a single call based on an actual pointer to a memory location. That would not account for polymorphism!

    Unless you are leaving out where it's getting the address of the function from by accident, this can't be true. The only explanation for what you're saying is that the compilers are noticing you are only using nonvirtual member functions and they internally implement them just as function pointers. Try the example you gave but use virtual member functions instead and call that member function through the pointer on different derivations of the base class. It can't possibly just go by single function pointer because that varies dependng on the object. It has to go through the vtable. If it didn't, then the same exact function would be called every time, which is against the standard.

    EDIT: Another explanation can be that it's a single function pointer, but not directly to the member function. The function it points to would have to call the appropriate function. The problems with this is that it'd be referring to a function that has to be implicitly created by the compiler, and it means that every time the member function is called it has to go through a pointer, which would be pretty much being doing the same thing -- dynamic binding on functions meant to be statically bound, plus, it also forces yet another step of dereferencing for ones that are meant to be dynamically bound. So that doesn't really get anywhere.

    I highly doubt that codewarrior would make sizeof return 12 unless it actually does take up that amount, simply because, in this case, they have absolutely no reason to. Even with struct padding, compilers have sizeof return the size that it actually takes up in memory. They're not going to give a false value just for the heck of it. It makes operations that deal with memory locations a hassle because the programmer would have a false view of what's going on, and in this case, just liek with padding, it really does matter. If you really want to check, make an array of 2 member function pointers, take their individual addresses, type cast the "pointers to pointer to member function" to "pointers to char" (which should be a valid cast, though I'd have to check), then subtract one from the other. I'm willing to bet it will give you the result of whatever sizeof returned.

    I guess the problem is that most of this is just educated guessing as to how they "probably" implement it and not exactly how they do. It's probably documented somewhere, so if anyone has links then post them.
    Last edited by Polymorphic OOP; 11-26-2002 at 11:39 PM.

  6. #21
    cereal killer dP munky's Avatar
    Join Date
    Nov 2002
    Posts
    655
    Originally posted by golfinguy4
    Redmond, Washington home of
    ... nintendo, microsoft, digipen???

    take your pic... i know the answer
    Last edited by dP munky; 11-26-2002 at 10:24 PM.
    guns dont kill people, abortion clinics kill people.

  7. #22
    Registered User
    Join Date
    Sep 2002
    Posts
    272
    Another explanation can be that it's a single function pointer, but not directly to the member function.
    This doesn't appear to be the case in release builds on VC.net. Based on the following -

    Code:
    class a
    {
    public:
    	void fun()
    	{
    		//
    	}
    
    };
    
    typedef  void (a::*amemfun)(); 
    
    int main()
    {
    	a ins;
    	amemfun e = a::fun;
    	
    	(ins.*e)();	
    	
    
    	return 0;
    }

    The relevant call in main is -

    Code:
    00401006  mov         dword ptr [ebp-4],offset a::fun (401020h) 
    0040100D  lea         ecx,[ebp-5] 
    00401010  call        dword ptr [ebp-4]

    The member function begins at 401020h -

    Code:
    ?fun@a@@QAEXXZ:
    00401020  push        ebp
    So it's not a jump into a table.

    Altering fun to a virtual function produces the code -

    Code:
    0040100E  mov         dword ptr [ebp-4],offset `vcall' (401060h) 
    00401015  lea         ecx,[ebp-8] 
    00401018  call        dword ptr [ebp-4]
    at 401060h is (the virtual table) -

    Code:
    ??_9@$BA@AE:
    00401060  mov         eax,dword ptr [ecx] 
    00401062  jmp         dword ptr [eax]
    which then jumps to the correct function.

    So based on this it would appear that it is determined at compile time whether the function pointer is to be used on non virtual functions on VC.net.
    Joe

  8. #23
    Programming Sex-God Polymorphic OOP's Avatar
    Join Date
    Nov 2002
    Posts
    1,078
    That's exactly my point. The only way that the compiler is going to be able to do that is through optimizations at compile time!

    The point is, it can't always make these optimizations. Of course, if you make a pointer to a member function and store the address of a member function to it in the same function, it's going to be able to adjust itself to either just make it like a "literal" function pointer, and if it's a virtual function it's going to know it just the same.

    The only way you can really test is:

    Make a function that has a parameter of a member function pointer. Within the function, call the member function on a particular object. The object should be dereferenced through a pointer that's either global or local to a class. Assign to the object pointer a derived version of the class somewhere in another function. This way, the function that calls the member function will not be able to know the datatype of the object and it won't know if the function is virtual or non virtual.

    Call that function with both a virtual member function pointer and a nonvirtual in the same program.

    That makes it impossible for the function to make the optimization of using a literal pointer. It would have no way of knowing at compile time which type of pointer will be stored, and the function would have to account for all cases -- virtual and nonvirtual for the datatype and all of its children.

  9. #24
    Registered User
    Join Date
    Sep 2002
    Posts
    272
    Of course, if you make a pointer to a member function and store the address of a member function to it in the same function, it's going to be able to adjust itself to either just make it like a "literal" function pointer
    Does it matter where the pointer is declared? If I did

    class a
    {
    public:
    void fun(){}
    };

    class b : public a
    {
    public:
    void fun(){}
    };

    Depending on my function pointer type, I've still got to point it at either

    a::fun

    or

    b::fun

    How is attempting to disguise the object type going to fool the compiler. Assuming fun is non-virtual it is clear which function is being called as the function has been assigned to the pointer. I'm not entirely sure what you're getting at (perhaps you could provide an example), but you can't assign the address of a bound member function to a pointer.

    The following code, assigns the address in the same way, and calls the member function directly -

    Code:
    class a
    {
    public:
    	void fun()
    	{	
    	}
    
    };
    
    class b : public a
    {
    	void fun()
    	{
    	}
    };
    
    typedef  void (a::*amemfun)(); 
    
    a* ga;
    
    void foo(amemfun amf)
    {
    	
    
    	((*ga).*amf)();	
    }
    
    void bar()
    {
    	ga = new b;
    }
    
    
    int main()
    {
    
    	
        bar();	
    
    	amemfun amf = a::fun;
    
    	foo(amf);
    
    	delete ga;
    
    	return 0;
    }
    Joe

  10. #25
    Programming Sex-God Polymorphic OOP's Avatar
    Join Date
    Nov 2002
    Posts
    1,078
    Originally posted by JoeSixpack
    How is attempting to disguise the object type going to fool the compiler. Assuming fun is non-virtual it is clear which function is being called as the function has been assigned to the pointer.
    Why? For the same reason that a virtual function is called through static binding when using a object -- not through a pointer. If you declare a member function pointer, initialize it to a constant, and use it in the same function, the compiler is going to see this and just make the optimization of calling it statically. The only way you can truly check what's happening is if you can make the compiler oblivious to what's going on until runtime.

    Just think logically about your example. If the pointer, as defined by the standard has to account for both static and dynamic binding, it can't possibly just call the function without making any other checks, because it is possible that the function is either virtual or nonvirtual! The only possible way it can just use a literal pointer is if the compiler itself noticed that you were using a nonvirtual function.

    If you want to be 100% sure, make a static link library function that returns a pointer to a member function. That way it is completely impossible for the function which uses that return value to make the optimization because they aren't related until linking.

    EDIT: Another thing you can try is declaring them all as volatile so that the compiler can't make any assumptions.
    Last edited by Polymorphic OOP; 11-27-2002 at 05:28 PM.

  11. #26
    Registered User
    Join Date
    Sep 2002
    Posts
    272
    If you want to be 100% sure, make a static link library function that returns a pointer to a member function. That way it is completely impossible for the function which uses that return value to make the optimization
    Why would the optimisation be done in the caller? When the library is compiled it'll do the same checks. If you're using a compiler that checks whether it's using 'addresses' of virtual or non-virtual functions, it could just return the 'address' of the member function if it's non-virtual. The library will have access to the same information about the class as the exe. The caller may be the only one that knows the exact object in an inheritance hierachy but if you're returning a pointer to a specific member function either it can use it or not (which the compiler will be able to deduce from the return type).

    Another thing you can try is declaring them all as volatile so that the compiler can't make any assumptions.
    What assumptions is the compiler making? It can see the class declaration so it knows whether it contains virtual members or not.
    Joe

  12. #27
    Programming Sex-God Polymorphic OOP's Avatar
    Join Date
    Nov 2002
    Posts
    1,078
    Originally posted by JoeSixpack
    [B]Why would the optimisation be done in the caller? When the library is compiled it'll do the same checks.[B]
    Because when used in the program which links to the library, it only sees the header during the compilation, so during compile time, that program has no way of knowing if it's returning a pointer to a virtual or nonvirtual member. If it's done in the same compiliation, however, it's possible that it can see this and interpret the "member to function pointer" as a more specific type.


    What assumptions is the compiler making? It can see the class declaration so it knows whether it contains virtual members or not.
    It's not a matter of whether or not it knows that the class has virtual functions or not, it's a matter of "Is it calling one of the virtual functions or is it calling one of the nonvirtual functions." Just because one function is virtual doesn't mean they all are, so the compiler still has to account for both cases. Both types have completely different calling conventions, so if it just said "this class has some virtual functions, I have to use a vtable offset" it would either have to use an offset for nonvirtual functions as well, or do any of the other things I mentioned. The one thing that it physically can NOT do without optimizations is call the function directly without making a check, explicitly through data in the member function "pointer," or through a nested function call. If it didn't, then it would have no way of accounting for both cases.

  13. #28
    Guest Sebastiani's Avatar
    Join Date
    Aug 2001
    Location
    Waterloo, Texas
    Posts
    5,708
    Well, I think Joe pretty much provided a concrete answer on how a certain compiler handled the matter. Even Fordy's tests on CodeWarrior gave the same results, leading me to believe this may be the norm, which is a relief!

    Question: what does the lea instruction do anyway?
    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. #29
    &TH of undefined behavior Fordy's Avatar
    Join Date
    Aug 2001
    Posts
    5,793
    Originally posted by Sebastiani
    Question: what does the lea instruction do anyway?
    Load Effective Address (I think anyway)

    Loads a memory offset into a register.....like a C pointer

  15. #30
    Registered User
    Join Date
    Sep 2002
    Posts
    272
    Because when used in the program which links to the library, it only sees the header during the compilation, so during compile time, that program has no way of knowing if it's returning a pointer to a virtual or nonvirtual member.
    I'm not exactly on the ball with C++ at the moment, but don't you have to specify whether a function is virtual in the declaration? Therefore the information will be in the header?

    It's not a matter of whether or not it knows that the class has virtual functions or not, it's a matter of "Is it calling one of the virtual functions or is it calling one of the nonvirtual functions." Just because one function is virtual doesn't mean they all are, so the compiler still has to account for both cases.
    Yes but surely the compiler can tell from the class declaration if a function is one of the virtual members. It can see the declaration in all compilation units. It's not making any assumptions.

    The only way I can see that this would be an issue (although I may be being blind), is if you can take the address of a bound member function. In which case it wouldn't be possible at compile time to determine it's exact type. However, as this illegal I can't figure out how it would be possible to hide the fact from a compiler that a function was virtual.

    Question: what does the lea instruction do anyway?
    As Fordy states plus it is used in this case to implicity pass the 'this' pointer into a member function via a register (ecx).
    Joe

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