Dirk Reiners wrote:


The basic problem is that the linker is too smart. We use static C++
objects quite a bit that register themselves with a factory when they
are instantiated. But a smart linker can see that none of the symbols
from that object file are used anywhere else in the program, and
conclude that the object file is not needed. The workaround is to
manually touch a symbol from the object file, which will force the
object file to be linked, which will in turn create the static object,
which can then register itself with the factory.
There is a technique called 'nifty-counter' which adresses this issue. It is described in John Lakos' great book "Large scale c++ software engineering". Basically, you do something like this:

foo.h:
class foo : public FactoryProduct { ... };
class fooInit { fooInit(); ~fooInit(); };
static fooInit s_initFoo;

foo.cpp:
int count = 0;
fooIinit() { if (count++ == 0) regWithFactory<Foo>(); }
~fooInit() { if(--count == 0) unregWithFactory<Foo>(); }

user_foo.cpp
#include <foo.h>

user_foo.cpp will have a reference to foo.cpp, so it will be accessible. Naturally, this is a general technique to assure that any class-global data is initialized before using the class itself. What we've done is to wrap the xxxInit declaration and implementation in some useful macros, and use layers of niftycounters. (If you have a macro DECLARE_NIFTYCOUNTER(fooInit) and IMPLEMENT_NIFTYCOUNTER then you do something like the following:)

foomodule.h:
DECLARE_NIFTYCOUNTER(fooModuleInit)

foomodule.cpp
DECLARE_NIFTYCOUNTER(foo)
DECLARE_NIFTYCOUNTER(bar)
IMPLEMENT_NIFTYCOUNTER(fooModuleInit)

.. and so on and so forth. This is quite useful since you don't have to include the entire header of foo, just have it's niftycounter class and a local instance of that class. Of course you can layer this, and have one header refering to foomodule.h-equivalents and thus having only one header to include in order to get all these dynamic objects from several modules referenced (or perhaps only some, depending on your application). Or in case of OpenSG, that could be included by osgInit()'s .cpp file.

The drawback of this is that if the work done in niftycounter-init is heavy, you may have delays before entering main(). But just registering classes in factories and similar things have not been a problem for us. Somewhat related to this is that if there are many singletons (such as the factory in the given example) in your application, you need to be careful about the order of construction/destruction, but doing that is not especially difficult.

Regards,
/Marcus







-------------------------------------------------------
SF.Net email is Sponsored by the Better Software Conference & EXPO
September 19-22, 2005 * San Francisco, CA * Development Lifecycle Practices
Agile & Plan-Driven Development * Managing Projects & Teams * Testing & QA
Security * Process Improvement & Measurement * http://www.sqe.com/bsce5sf
_______________________________________________
Opensg-users mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/opensg-users

Reply via email to