2

My project uses self registering classes in two ways: the one is to implement factory pattern, which allows to iterate map of this classes, the implementation is almost completely similar to the one described in C++ how safe are self registering classes?; and the other is to separate huge switch statement into map of objects. In the latter case I have just created one base class and a set of derived classes, then I instantiated each of derived classes with static object in the source file, while constructors of classes register themself in a map.

Now I'm trying to move the logic part of my app into static library and use this library in two subprojects (I use Qt, Qt Creator and gcc). After doing so, none of the above-described classes are work unless I do an exlicitly instantiation of such classes somewhere.

So, I'm looking for any workarounds. Actually, another question is arising: was it a very bad intension to design an application in c++ using self registering techniques?

EDIT: I was asked to give an example. Here is simplified code:

// Class for storing actions
class ActionBase;
class SomeObject;    
class ActionMap
{
    public:
    ActionMap();
    static void registerAction(int n, ActionBase* action) {}
    void performAction (SomeObject* object, int action) {
         m_actions[action]->perform(object);
    }

 private:
     std::map<int, ActionBase*> m_actions;
};

// Action class - action.h
#include "actionmap.h"
class SomeObject;
class ActionBase
{
public:
     ActionBase(int n, ActionBase* action) {ActionMap::registerAction(n, action); }
     virtual ~ActionBase() = 0;
     virtual void perform(SomeObject* object) = 0;
 };

 template<int N>
 class Action : public ActionBase
 {
 public:
    Action() : ActionBase(N, this) {}
 };

 template<>
 class Action<1> : public ActionBase
 {
 public:
     Action() : ActionBase(1, this) {}
     void perform(SomeObject* object)
     {
      // Do something
     }
 };

Now I can create some action object in actions source file, something like:

// action.cpp
// #include "action.h"
static Action<1> action1;

After restructuring project, I have to create action1 variable somewhere in my subproject explicitly to be enable to use it, for example in the main.cpp.

Update: it seems that Angew helped me to partially solve the second problem. I have decleared a free empty function and defined it in action.cpp. Calling it somewhere in the app forces initialization of action objects.

Community
  • 1
  • 1
qloq
  • 689
  • 1
  • 5
  • 15
  • _"none of the above-described classes are work unless"_ you need to explain this a bit more and try to include an [MCVE] – Richard Critten Mar 14 '17 at 12:30
  • @RichardCritten this is most probably the linker dropping the object file containing the registering instance, because nobody references it. Broken behaviour if you ask me, but here we are. – Quentin Mar 14 '17 at 12:32
  • @Quentin Not necessarily. Don't forget that in C++, file-scope variables are only guaranteed to be initialised before any code from that file is executed, but they can be initialised after `main` has started. – Angew is no longer proud of SO Mar 14 '17 at 12:36
  • @Angew I'm glad you made me [check](http://en.cppreference.com/w/cpp/language/initialization#Deferred_dynamic_initialization). TIL this is in fact explicitly implementation-defined... Well that's a bummer for static registering objects :/ – Quentin Mar 14 '17 at 12:41
  • The solution to your question is in the following answer: https://stackoverflow.com/a/25344326/5938816 – Dmitriy Zapevalov Jan 10 '19 at 21:37

1 Answers1

3

was it a very bad intension to design an application in c++ using self registering techniques?

I am afraid I have to answer "yes" to this one. C++ explicitly allows non-local variables to be initialised after main has started; the only constraint is that they must be initialised before any code from the file which defines them is executed. Quoting C++14 (N4140) [basic.start.init] 3.6.3/4:

It is implementation-defined whether the dynamic initialization of a non-local variable with static storage duration is done before the first statement of main. If the initialization is deferred to some point in time after the first statement of main, it shall occur before the first odr-use (3.2) of any function or variable defined in the same translation unit as the variable to be initialized.

In other words, it is possible that a global variable defined in a file, whose initialisation does some registration, will not be initialised (and thus registered) until some other code from that file is called.

Angew is no longer proud of SO
  • 167,307
  • 17
  • 350
  • 455