Any overhead when inheriting from class with only static members?

Started by
5 comments, last by Prune 12 years, 4 months ago
I have a class A with only static members, where I want to lazily initialize said members: at first construction (if such even occurs) of an object from some other classes B, C... that rely on A being initialized, rather than during program startup. However, rather than calling A::Init() in the ctors of B, C..., I want that to happen automatically whenever an object of those classes is created. So I put the initialization in the ctor of A, and made B, C... derive from A. My question is whether there is any performance impact whatsoever of doing this, versus not having the inheritance and just calling A::Init() in the ctors explicitly instead. The sizes of B, C... of course are not impacted, and I don't think a vtable would be generated because there's no polymorphism possible, but I wanted to ask so I can be sure.
"But who prays for Satan? Who, in eighteen centuries, has had the common humanity to pray for the one sinner that needed it most?" --Mark Twain

~~~~~~~~~~~~~~~Looking for a high-performance, easy to use, and lightweight math library? http://www.cmldev.net/ (note: I'm not associated with that project; just a user)
Advertisement
The compiler should skip v-table generation if a class has no virtual functions. Compile your project with optimisations on and check the assembly code. This is the only way to ensure that the desired "micro optimisations" are actually being performed.
Thanks.
"But who prays for Satan? Who, in eighteen centuries, has had the common humanity to pray for the one sinner that needed it most?" --Mark Twain

~~~~~~~~~~~~~~~Looking for a high-performance, easy to use, and lightweight math library? http://www.cmldev.net/ (note: I'm not associated with that project; just a user)

Thanks.

Just wondering why you only have class static variables in the base class, do these need to be the same for all instances of the objects. Also bear in mind that when you change the value in either B or C instances the will change for all derived types using them and all existing instance.

Worked on titles: CMR:DiRT2, DiRT 3, DiRT: Showdown, GRID 2, theHunter, theHunter: Primal, Mad Max, Watch Dogs: Legion

Yes, it's shared value. Basically it's just to lazy-initialize a handle to an NT keyed event, which I then use for the sleeping slow-path of various synchronization primitives like mutexes, condvars, and so on. I just didn't want to initialize it unless one of those dependent classes was actually used.
"But who prays for Satan? Who, in eighteen centuries, has had the common humanity to pray for the one sinner that needed it most?" --Mark Twain

~~~~~~~~~~~~~~~Looking for a high-performance, easy to use, and lightweight math library? http://www.cmldev.net/ (note: I'm not associated with that project; just a user)
There should be no performance penalty whatsoever (but then again, some compilers are weird.)

However, there are a couple of corner case caveats with this kind of lazy initialization. The first is that it's obviously not thread safe unless you've made it explicitly so. Second is that where initialization happens is unpredictable (although that is rarely an issue unless the Init function has serious side effects.) And the third caveat is that static variables are kind of funky if used eg. in a shared library (you could end up with duplicate values.)
I have it in an atomic compare-exchange loop so it's thread safe. I'm just doing the equivalent of std::call_once() for initialization but instead of using a separate once_flag, I'm storing the flag in the pointer itself since no valid pointer will be 0 or 1. This saves space. (got the idea from singleton article at lockless inc site)
[source lang="cpp"]
void *cur(LoadAcq(_handle));
while (reinterpret_cast<unsigned long>(cur) <= 1) // While uninitialized or contended
{
if (!cur && !AtomicCAS(reinterpret_cast<unsigned long *>(&_handle), 0, 1)) // Try to set contended
{
try
{
void *temp(Init()); // Load ntdll and the relevant functions and create keyed event
StoreRel(_handle, temp);
return;
}
catch (...)
{
StoreRel(_handle, nullptr); // Other threads should be able to retry
throw;
}
}
Pause();
cur = LoadAcq(_handle);
}
[/source]
"But who prays for Satan? Who, in eighteen centuries, has had the common humanity to pray for the one sinner that needed it most?" --Mark Twain

~~~~~~~~~~~~~~~Looking for a high-performance, easy to use, and lightweight math library? http://www.cmldev.net/ (note: I'm not associated with that project; just a user)

This topic is closed to new replies.

Advertisement