Getting Rid of overhead of virtual functions

Started by
19 comments, last by haro 21 years, 1 month ago
I''ve read that there is significant overhead on heavily using virtual functions, and was curious if there is a common way to alleviate this overhead. In my case I am using a base win32 wrapper class which contains a number of virtual functions such as: getSurface(), drawLine(Point p1, Point p2, ColorRGB color) and a multitude of other functions including stuff for rendering a triangle strip, getting a list of vertices for a triangle strip/fan, etc... Needless to say 90% of my program will be calling and using virtual functions, but this is the only really decent way to write the program to allow for seamless use of DirectX or OpenGL, which is what I want to do. If there is overhead its going to bite me soon, and I''m trying to get rid of it before the project becomes too large to change within a reasonable time frame. Anyhow, what''s the common opinion on implementing virtual functions and their overhead? Thanks. The project is written in C++/VC7.0.
Advertisement
The DirectX API uses interfaces, which are basically classes populated only with virtual functions. The overhead might show up if you go crazy with virtual functions, but otherwise I wouldn''t worry about it. It''s never affected me before.

Someone correct me if it''s a more serious problem than I think it is.

quote:
I''ve read that there is significant overhead on heavily
using virtual functions, and was curious if there is a
common way to alleviate this overhead.


If you need run-time dispatch, you''ll find out that you need each and every step a virtual function call does, and that talking of "overhead" is complete nonsense. Overhead compared to what ? Non-virtual function calls don''t offer the same functionality. You want the functionality, you pay the price.

And figuring out whether you need it or not is part of a programmer''s job.

In the most common implementation, the overhead consists in looking up the function address in a table instead of having it ''hard-coded''. The table is selected by a hidden pointer stored in every object of classes which have virtual functions.

On the other hand, when the compiler knows unambiguously the type of the object (Foo f; f.vfunc();), it usually directly generates the right address.

If only for this reason, you don''t want to reimplement virtual functions yourself. Odds are the compiler won''t go "Aha ! He''s trying to reimplement virtual functions !", and generate code less efficient than for what it knows to be virtual functions.

At any rate, the overhead is not significant unless you are calling such a function repeatedly in a tight loop. If you know you have an homogeneous set of objects (all Foos), you can dispense from the virtual function call, and use a non-virtual function ( define two functions, the virtual one calls the non-virtual - or, with gcc and borland c++ you can ''freeze'' the virtual function, but not with VC). If not, you don''t have a choice.

[ Start Here ! | How To Ask Smart Questions | Recommended C++ Books | C++ FAQ Lite | Function Ptrs | CppTips Archive ]
[ Header Files | File Format Docs | LNK2001 | C++ STL Doc | STLPort | Free C++ IDE | Boost C++ Lib | MSVC6 Lib Fixes ]
"Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it." — Brian W. Kernighan
As mentioned, the calling overhead is minimal compared to the functionality you gain. The only other aspect to consider is that of memory. If you are working in a very tight memory model, you should be aware that virtual functions can take up to three times as much memory to make the call (I don''t know why exactly, it''s something to do with creating additional pointers for the virtual pointing). But as the non-virtual pointers take up very little memory anyway, you would have to be using an extremely limited memory model before this became an issue.
------------------------------------------[New Delta Games] | [Sliders]
quote:Original post by haro
Needless to say 90% of my program will be calling and
using virtual functions, but this is the only really
decent way to write the program to allow for seamless
use of DirectX or OpenGL, which is what I want to do.
Not really the only decent way. With a heavy use of templates, you could have two totally separate class systems: one for OpenGL, one for DirectX. There''s no need to mix between these two so templates would work out well, and you could get rid of ALL the virtual functions whose sole purpose is to enable the use of both OpenGL and DirectX. BUT: your compile times would increase significantly since every class should be templatized and template classes must be placed on headers (so long, precompiled code).

Okay, so maybe templates don''t qualify as a ''decent way''.
it''s not just compile times that would increase. there would be a significant increase in the size of the executable produced when you make heavy use of templates.
The curiously recurring template pattern can also be used in some situation.
daerid@gmail.com
quote:Original post by Damocles
If you are working in a very tight memory model, you should be aware that virtual functions can take up to three times as much memory to make the call (I don''t know why exactly, it''s something to do with creating additional pointers for the virtual pointing).


Pointers to virtual member functions may indeed be larger than pointers to non-virtual member functions, but that doesn''t affect you unless you are explicitely creating such a pointer. The compiler doesn''t need them to make a call.

The only real memory cost is the virtual function table pointer in each object. If the objects are otherwise small and you have many of them, that cost may be significant. The cost of the virtual function tables itself is insignificant, unless you have billions of classes, which would either mean an astronomical object count or a really inept programmer.

And don''t go about creating your own type field, it won''t buy you anything in practice in most cases and will become a maintenance nightmare in short time.

quote:Original post by daerid
The curiously recurring template pattern can also be used in some situation.


That''s a structural pattern, not a behavioral pattern.
It saves you some typing, but does nothing at run-time.

[ Start Here ! | How To Ask Smart Questions | Recommended C++ Books | C++ FAQ Lite | Function Ptrs | CppTips Archive ]
[ Header Files | File Format Docs | LNK2001 | C++ STL Doc | STLPort | Free C++ IDE | Boost C++ Lib | MSVC6 Lib Fixes ]
"Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it." — Brian W. Kernighan
Thanks for all the feedback. I think I''ll probably
just stay with the the current model after all.
quote:Original post by Fruny
That''s a structural pattern, not a behavioral pattern.
It saves you some typing, but does nothing at run-time.


It''s a way to simulate inheritance without having vtables or virtual function pointers.
daerid@gmail.com

This topic is closed to new replies.

Advertisement