Search code examples
c++c++11templatesfactory-pattern

Unforgettable Factory: When is constructor instantiated?


I'm implementing the unforgettable factory. Everything works fine but one thing: The classes are not registered, sometimes.

I think the crucial part is the Registrar::registered member. If it is used, "The really fun part" calls the registerT function which registers the class.

In my toy example, the class is not registered unless either

  1. the constructor is implemented (in cpp-file or inline). Explicit default constructor and constructor inheritance (*) do not register the class.
  2. there is a virtual method in the base class (Animal), which is overridden in the registered class and implemented in cpp-file. Inline implementation does not work (unlike inline ctor).

Did I make a mistake or did the author miss something? In my real-world application, some classes are registered and some are not and I cannot spot the difference (all classes satisfy (1.)), that's why I must deepen my understanding.

My question is: Under which circumstances exactly is registerT called? In other words: When is the constructor of Registrar instantiated? Where should I put the (void) registered; such that it is always instantiated?

(*) to make constructor inheritance work, I made the constructors of Factory and Factory<...>::Registrar public

Edit: this question pointed me to the unforgettable factory blog post. This is not a duplicate. The author of that question apparently only forgot to add "The really fun part" and the crucial almost-empty-constructor. I didn't forget them. I want to know why this crucial almost-empty-constructor is not instantiated although it is there.

Edit: The solution was not to use the proposed pattern. It does not seem to be fit for production code, see the relevant issue.


Solution

  • [basic.start.dynamic]/3 A non-initialization odr-use is an odr-use (6.2) not caused directly or indirectly by the initialization of a non-local static or thread storage duration variable.

    [basic.start.dynamic]/4 It is implementation-defined whether the dynamic initialization of a non-local non-inline variable with static storage duration is sequenced before the first statement of main or is deferred. If it is deferred, it strongly happens before any non-initialization odr-use of any non-inline function or non-inline variable defined in the same translation unit as the variable to be initialized.

    This is what causes this and similar self-registration schemes to fail. There's a translation unit containing definitions of entities that are not referenced elsewhere in the program, but only by the initializer of a static variable defined in that same translation unit. The implementation may choose to defer the initialization of that static variable until anything in its translation unit is odr-used - which is never.