Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

static initialization

Tags:

c++

the context

I'm working on a project having some "modules". What I call a module here is a simple class, implementing a particular functionality and derivating from an abstract class GenericModule which force an interface.

New modules are supposed to be added in the future.

Several instances of a module can be loaded at the same time, or none, depending on the configuration file.

I though it would be great if a future developer could just "register" his module with the system in a simple line. More or less the same way they register tests in google test.

the context² (technical)

I'm building the project with visual studio 2005. The code is entirely in a library, except the main() which is in an exec project. I'd like to keep it that way.

my solution

I found inspiration in what they did with google test.

I created a templated Factory. which looks more or less like this (I've skipped uninteresting parts to keep this question somewhat readable ):

class CModuleFactory : boost::noncopyable
{
public:
    virtual ~CModuleFactory() {};

    virtual CModuleGenerique* operator()(
        const boost::property_tree::ptree& rParametres ) const = 0;
};

template <class T>
class CModuleFactoryImpl : public CModuleFactory
{
public:
    CModuleGenerique* operator()(
        const boost::property_tree::ptree& rParametres ) const
    {
        return new T( rParametres );
    }
};

and a method supposed to register the module and add it's factory to a list.

class CGenericModule
{
    // ...
    template <class T>
    static int declareModule( const std::string& rstrModuleName )
    {
        // creation de la factory
        CModuleFactoryImpl<T>* pFactory = new CModuleFactoryImpl<T>();

        // adds the factory to a map of "id" => factory
        CAcquisition::s_mapModuleFactory()[rstrModuleName ] = pFactory;

        return 0;
    }
};

now in a module all I need to do to declare a module is :

static int initModule =
acquisition::CGenericModule::declareModule<acquisition::modules::CMyMod>(
    "mod_name"
    );

( in the future it'll be wrapped in a macro allowing to do

DECLARE_MODULE( "mod_name", acquisition::modules::CMyMod );

)

the problem

Allright now the problem.

The thing is, it does work, but not exactly the way i'd want.

The method declareModule is not being called if I put the definition of the initModule in the .cpp of the module (where I'd like to have it) (or even in the .h). If I put the static init in a used .cpp file .. it works.

By used I mean : having code being called elsewhere.

The thing is visual studio seems to discard the entire obj when building the library. I guess that's because it's not being used anywhere.

I activated verbose linking and in pass n°2 it lists the .objs in the library and the .obj of the module isn't there.

almost resolved?

I found this and tried to add the /OPT:NOREF option but it didn't work. I didn't try to put a function in the .h of the module and call it from elsewhere, because the whole point is being able to declare it in one line in it's file.

Also I think the problem is similar to this one but the solution is for g++ not visual :'(

edit: I just read the note in the answer to this question. Well if I #include the .h of the module from an other .cpp, and put the init in the module's .h. It works and the initialization is actually done twice ... once in each compilation unit? well it seems it happens in the module's compilation unit ...

side notes

Please if you don't agree with what I'm trying to do, fell free to tell, but I'm still interested in a solution

like image 327
f4. Avatar asked Jun 23 '10 19:06

f4.


People also ask

What do you mean by static initialization give an example?

Example. Live Demo public class Demo { static int[] numArray = new int[10]; static { System. println("Running static initialization block."); for (int i = 0; i < numArray. length; i++) { numArray[i] = (int) (100.0 * Math.

What is static initialization in C++?

Static initialization happens first and usually at compile time. If possible, initial values for static variables are evaluated during compilation and burned into the data section of the executable. Zero runtime overhead, early problem diagnosis, and, as we will see later, safe. This is called constant initialization.

What is static and dynamic initialization?

The difference between static initialization and dynamic initialization: A static initialization in java is a particular block that is made to run before the main () method in java whereas dynamic initialization refers to the initiation of the project during the rum time.

Why do we need to initialize static variables?

When static keyword is used, variable or data members or functions can not be modified again. It is allocated for the lifetime of program. Static functions can be called directly by using class name.


2 Answers

If you want this kind of self-registering behavior in your "modules", your assumption that the linker is optimizing out initModule because it is not directly referenced may be incorrect (though it could also be correct :-).

When you register these modules, are you modifying another static variable defined at file scope? If so, you at least have an initialization order problem. This could even manifest itself only in release builds (initialization order can vary depending on compiler settings) which might lead you to believe that the linker is optimizing out this initModule variable even though it may not be doing so.

The module registry kind of variable (be it a list of registrants or whatever it is) should be lazy constructed if you want to do things this way. Example:

static vector<string> unsafe_static; // bad

vector<string>& safe_static()
{
    static vector<string> f;
    return f;
} // ok

Note that the above has problems with concurrency. Some thread synchronization is needed for multiple threads calling safe_static.

I suspect your real problem has to do with initialization order even though it may appear that the initModule definition is being excluded by the linker. Typically linkers don't omit references which have side effects.

If you find out for a fact that it's not an initialization order problem and that the code is being omitted by the linker, then one way to force it is to export initModule (ex: dllexport on MSVC). You should think carefully if this kind of self-registration behavior really outweighs the simple process of adding on to a list of function calls to initialize your "modules". You could also achieve this more naturally if each "module" was defined in a separate shared library/DLL, in which case your macro could just be defining the function to export which can be added automatically by the host application. Of course that carries the burden of having to define a separate project for each "module" you create as opposed to just adding a self-registering cpp file to an existing project.

like image 109
stinky472 Avatar answered Oct 23 '22 19:10

stinky472


I've got something similar based on the code from wxWidgets, however I've only ever used it as a DLL. The wxWidgets code works with static libs however.

The bit that might make a difference is that in wx the equivelant of the following is defined at class scope.

static int initModule =
acquisition::CGenericModule::declareModule<acquisition::modules::CMyMod>(
    "mod_name"
    );

Something like the following where the creation of the Factory because it is static causes it to be loaded to the Factory list.

#define DECLARE_CLASS(name)\
class name: public Interface { \
    private: \
        static Factory m_reg;\
        static std::auto_ptr<Interface > clone();

#define IMPLEMENT_IAUTH(name,method)\
    Factory name::m_reg(method,name::clone);\
like image 1
Greg Domjan Avatar answered Oct 23 '22 19:10

Greg Domjan