(This editor has a problem today, all my format is messed up, sorry!) )
Inheritance is an important feature of OOP. Although many peers in the industry do not like inheritance, the correct use of inheritance is an important design decision at the application and architectural levels. How does the use of inheritance, especially in the STD container, affect program performance?
From my personal experience, constructor has a great influence on the creation of class with deep inheritance chains. If the application allows, it is best to use a base class without constructor. Here's an example:
struct __declspec (novtable) ITest1
{virtual void AddRef () = 0;
virtual void Release () = 0;
virtual void DoIt (int x) = 0; };
Class Ctest:public ITest1
{
int ref;
Public:inline CTest () {ref = 0;}
inline void AddRef () {++ref;}
inline void Release () {--ref;}
inline void DoIt (int x) {ref *= x;}
inline void AddRef2 () {++ref;}
inline void Release2 () {--ref;}
inline void DoIt2 (int x) {ref *= x;}
static void Testperf (int loop); };
This is a dummy program, but it is common in COM. If we're going to create and use CTest a lot, experienced programmers should see that ITest1 doesn't need constructor at all. According to the C + + manual, ITest1 because of the virtual function, belonging to the "non-Simple construction Class", the compilation must produce a constructor, its sole purpose is to set the ITest1 vtbl (virtual function table).
However, the only function of interface is to be inherited, so its vtbl must be set by its inheriting class. Compiling in this case does not need to generate constructor. Microsoft was aware of this when designing ATL and launched its own solution to avoid the flaw of the C + + official Spec: VC + + provided the novtable class modifier, telling the compiler: I don't need your constructor. However, my test results in VS 2010 were disappointing:
ITest1 's constructor is still generated, but it does not assign a value to the vtbl , which is a little bit of a drop to improve the performance of the base class structure. Let's look at the effects of this "useless constructor" on performance. We right vote take out another itestpod that doesn't need a virtual function (the pod means "data") to do the comparison:
struct Itest1pod
{inline void AddRef () {}
inline void Release () {}
inline void DoIt (int x) {}};
Itestpod of course not fully used for interface (interface must use virtual functions), just to test. We then design an inheritance class that is exactly the same as the CTest function above:
Class Ctestpod:public Itest1pod
{
int ref;
Public:inline ctestpod () {ref = 0;}
inline void AddRef () {++ref;}
inline void Release () {--ref;}
inline void DoIt (int x) {ref *= x;}
};
Our aim is to use this ctestpod to make a comparison with ctest apples and apples:
void Ctest::testperf (int loop)
{
clock_t begin = Clock ();
for (int i = 0; I < loop; ++i)//LOOP1
{
Ctestpod testpod; Line1
Testpod.addref ();
Testpod.doit (0);
Testpod.release ();
}
clock_t end = Clock ();
printf ("POD time:%f \ n", double (End-begin)/clocks_per_sec);
begin = Clock ();
for (int i = 0; I < loop; ++i)//LOOP2
{
CTest test; Line2
Test. AddRef2 ();
Test. DOIT2 (0);
Test. Release2 ();
}
end = Clock ();
printf ("Interface time:%f \ n", double (End-begin)/clocks_per_sec);
}
The only difference between Loop1 and loop2 above is line1 and line2, in order to avoid the use of virtual functions, I specially prepared ctest for ADDREF2,DOIT2,RELEASE2, three identical but non-virtual functions, To follow a major principle of performance testing: compare Apple to Apple.
I set the loop to 100,000, and the test results showed that the LOOP2 was about 20% lower than the LOOP1 speed. The only difference from the generated code is that the CTest constructor calls the constructor of the compiled auto-generated ITest1. This constructor has no effect, but White takes up a lot of CPU cycles. A good compilation, it should be able to cut off the constructor, this depends on our own to search.
Summarize
When applying inheritance, removing useless constructor from the base class will have a significant effect on the performance of a large number of constructed object. Unfortunately, Microsoft's __declspec (novtable) class modifier did not provide any help to solve the problem. In the application of object design for mass storage, we should try to use Pod as the base class to avoid the obvious performance vulnerability of the above CTest class.
2014-9-3 Seattle
C + + Performance profiling (iv): Impact of inheritance on performance