This a question related to the initialization of objects in C++.
I have a group of classes (not instances), inheriting from a common base class, and I need them to register info about themselves in a container (specifically a map) when the program starts.
The problem is that I need it to be dynamic. The container is defined in an independent project, different from the classes. I would prefer to avoid making multiple hard-coded versions of the library, one for each set of classes in each program that uses it.
I thought about having a static instance of a special class in each of these subclasses, that would make the registration in its constructor. However, I have found no way to guarantee that the container will be constructed before the construction of these objects.
I should also note that the information in the container about the subclasses should be available before any instance of these subclasses is created.
Is there a way to do this, or imitate a static constructor in C++ in general?
You are describing different problems all at once. On the particular issue of having some sort of static initialization, a simple approach is creating a fake class that will perform the registration. Then each one of the different classes could have a static const X member, the member will have to be defined in a translation unit, and the definition will trigger the instantiation of the instance and the registration of the class.
This does not tackle the hard problem, which is the initailization order fiasco. The language does not provide any guarantee on the order of initialization of objects in different translation units. That is, if you compile three translation units with such classes, there is no guarantee on the relative order of execution of the fake member. That is also applied to the library: there is no guarantee that the container in which you want to register your classes has been initialized, if such container is a global/static member attribute.
If you have access to the code, you can modify the container code to use static local variables, and that will be a step forward as to ensure the order of initialization. As a sketch of a possible solution:
// registry lib
class registry { // basically a singleton
public:
static registry& instance() { // ensures initialization in the first call
static registry inst;
return inst;
}
// rest of the code
private:
registry(); // disable other code from constructing elements of this type
};
// register.h
struct register {
template <typename T>
register( std::string name ) {
registry::instance().register( name, T (*factory)() ); // or whatever you need to register
}
};
// a.h
class a {
public:
static a* factory();
private:
static const register r;
};
// a.cpp
const register a::r( "class a", a::factory );
// b.h/b.cpp similar to a.h/a.cpp
Now in this case there is no definite order among the registration of the a and b classes, but that might not be an issue. On the other hand, by using a local static variable in the registry::instance function the initialization of the singleton is guaranteed to be performed before any call to the registry::register methods (as part of the first call to the instance method).
If you cannot make that change you are basically out of luck and you cannot guarantee that the registry will be instantiated before the other static member attributes (or globals) in other translation units. If that is the case, then you will have to postpone the registration of the class to the first instantiation, and add code to the constructor of each class to be registered that ensures that the class is registered before actual construction of the object.
This might or not be a solution, depending on whether other code creates objects of the type or not. In the particular case of factory functions (first one that came to mind), if nothing else is allowed to create objects of types a or b... then piggy backing registration on constructor calls will not be a solution either.
This is a candidate for the Singleton pattern. Basically, you want the container to be instantiated when the first instance of a subclass is instantiated. This can be facilitated by checking if the singleton pointer is NULL in the base-class constructor, and if so, then instantiate the container.
One idea is to pass a registration functor to the classes. Each descendant would execute the function to register. This functor could be passed in the constructor.
Example:
struct Registration_Interface
{
virtual void operator() (const std::string& component_name) = 0;
};
struct Base
{
};
struct Child1
: public Base
{
Child(Registration_Interface& registration_ftor)
{
//...
registration_ftor("Child1");
}
};
See: http://www.parashift.com/c++-faq-lite/ctors.html#faq-10.14
One option is to construct the container lazily, when the first thing is added to it:
void AddToContainer(...) {
// Will be initialized the first time this function is called.
static Container* c = new Container();
c->Add(...);
}
The only way to "imitate" a static constructor is to explicitly call a function to perform your static initialization. There is no other way to run code pre-main just by linking in a module.
You might use an "initialise on first use" pattern, and then instantiate a dummy static instance to ensure initialisation as early as possible.
class cExample
{
public :
cExample() ;
// Static functions here
private :
static bool static_init ;
// other static members here
}
cExample::static init = false ;
cExample::cExample()
{
// Static initialisation on first use
if( !static_init )
{
// initialise static members
}
// Instance initialisation here (if needed)
}
// Dummy instance to force initialisation before main() (if necessary)
static cExample force_init ;
It is against OOP paradigm, but how about having your static members form a linked list guided by 2 global variables? You could do something like that:
ClassRegistrator *head = nullptr;
ClassRegistrator *tail = nullptr;
struct ClassRegistrator {
// ... Data that you need
ClassRegistrator *next;
ClassRegistrator(classData ...) {
if (!head)
head = tail = this;
else {
tail->next = this;
tail = this;
}
// ... Do other stuff that you need for registration
}
};
// The class you want to register
class MyClass {
static ClassRegistrator registrator;
}
ClassRegistrator MyClass::registrator(...); // Call the constructor
I believe the global variables, as they don't need have a constructor, but are just pure data, are guaranteed to be already initialised when you begin the execution of your code.
Obviously this is not thread-safe, etc, but should make your job done.
Related
In my program I need a factory function that provides instances of separate class because I need control over the details of each instance and to be aware of how many instances are in existence at a time. In particular returning a std::shared_ptr is ideal, but this is initially impossible due to a known issue with the "make" fucntions of the std::pointer types as they would need to be friends with my Widget class as well, which isn't portable since it relies on the current implementation of those methods that may change.
To get around this, I want to employ the Passkey idiom, which was directly recommend for this situation as described at the bottom of this: https://abseil.io/tips/134. I also based my implementation off the lessons learned here: https://arne-mertz.de/2016/10/passkey-idiom/
This is a sample project that uses my same setup as my full project:
#include <iostream>
class Widget
{
public:
class Key
{
friend class Factory;
private:
Key() {};
Key(const Key&) = default;
};
int mTest;
explicit Widget(Key, int test) { mTest = test; }
int getTestVar() { return mTest; }
};
class Factory
{
public:
int mTestPass;
Factory(int input) { mTestPass = input; }
std::shared_ptr<Widget> factoryMake() { return std::make_shared<Widget>(Widget::Key{}, mTestPass); }
};
int main()
{
Factory testFactory(10);
std::shared_ptr<Widget> testWidget = testFactory.factoryMake();
std::cout << testWidget->getTestVar();
return 0;
}
However, I get
Error C2248 'Widget::Key::Key': cannot access private member declared in class 'Widget::Key' TestProject ...\include\xmemory 204
This has me completely lost, since the error coming from xmemory.cpp indicates that std::make_shared is sill trying to access a private constructor. As far as I'm aware, the construction of the Key instance occurs within the factoryMake() function, which belongs to Factory, and then that instance is passed into the std::make_shared function; therefore, std::make_shared should not need access to the Key constructor since an already constructed instance is being passed to it, which is the entire point of using this idiom in this context. The class itself is public so it should have no issues interacting with the type Key, only the constructor should be inaccessible.
In the end I can just skip using std::make_shared and instead use the shared_ptr(*T) constructor with a raw pointer, but this is slightly less efficient due to the extra allocation it requires, as noted in my first link. It isn't a big deal as I'm not making many widgets but I'd ultimately prefer to get the more ideal implementation working.
What am I missing here?
The problem is that the compiler needs to copy your Widget::Key when you call std::make_shared, and you have declared the copy constructor private. You can solve this in one of two ways:
Make the copy constructor of Widget::Key public.
Change the Widget constructor to take the Widget::Key by const reference:
explicit Widget(const Key&, ...
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.
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.
So I have a class with static variables, the reason they are static is for (while it may seem insignificant) efficiency (only being required to load once, reduce redundancy of storage in memory of the same file).
Anyway what I'd like to know, is there a way to check if a variable has been loaded?
Or is there a way to have a specific constructor called the first time an instance of this class is created and another used while other instances exist?
If neither of these are appropriate what is the solution?
If your static members are private, and initialized in the same translation unit as all of your class's member functions, then the standard guarantees that the static members will be initialized before they are used. See: When are static C++ class members initialized?
There are other situations where this guarantee does not help you (e.g. accessing non-private static members from another translation unit, or from inline member functions).
You can play games with isInitialized flags, but be aware that without further work this is not thread-safe.
The C++ FAQ recommends to wrap static class instances in functions, this ensures that they are initialized on first use. e.g.:
Fred& x()
{
static Fred* ans = new Fred();
return *ans;
}
Source: https://isocpp.org/wiki/faq/ctors#static-init-order-on-first-use
Here you go:
class Test {
static bool isInitialized;
public:
Test() {
if (!isInitialized) {
// do whatever you need here
// ...
isInitialized = true;
}
}
};
bool Test::isInitialized = false;
You may do something like:
struct StaticData
{
// some variables
};
class YourClass
{
public:
YourClass(/*..*/) {
if (staticData == nullptr) {
staticData = std::make_unique<StaticData>(/*..*/)
}
}
private:
static std::unique_ptr<StaticData> staticData;
};
static std::unique_ptr<StaticData> YourClass::staticData;
I'm making a game engine and I'm using libraries for various tasks. For example, I use FreeType which needs to be initialized, get the manager and after I don't use it I have to de-initialize it. Of course, it can only be initialized once and can only be de-initialized if it has been initialized.
What I came up with (just an example, not "real" code [but could be valid C++ code]):
class FreeTypeManager
{
private:
FreeTypeManager() {} // Can't be instantiated
static bool initialized;
static TF_Module * module; // I know, I have to declare this in a separate .cpp file and I do
public:
static void Initialize()
{
if (initialized) return;
initialized = true;
FT_Initialize();
FT_CreateModule(module);
}
static void Deinitialize()
{
if (!initialized) return;
initialized = false;
FT_DestroyModule(module);
FT_Deinit();
}
};
And for every manager I create (FreeType, AudioManager, EngineCore, DisplayManager) it's pretty much the same: no instances, just static stuff. I can see this could be a bad design practice to rewrite this skeleton every time. Maybe there's a better solution.
Would it be good to use singletons instead? Or is there a pattern suiting for my problem?
If you still want the singleton approach (which kind of makes sense for manager-type objects), then why not make it a proper singleton, and have a static get function that, if needed, creates the manager object, and have the managers (private) constructor handle the initialization and handle the deinitialization in the destructor (though manager-type objects typically have a lifetime of the whole program, so the destructor will only be called on program exit).
Something like
class FreeTypeManager
{
public:
static FreeTypeManager& get()
{
static FreeTypeManager manager;
return manager;
}
// Other public functions needed by the manager, to load fonts etc.
// Of course non-static
~FreeTypeManager()
{
// Whatever cleanup is needed
}
private:
FreeTypeManager()
{
// Whatever initialization is needed
}
// Whatever private functions and variables are needed
};
If you don't want a singleton, and only have static function in the class, you might as well use a namespace instead. For variables, put them in an anonymous namespace in the implementation (source) file. Or use an opaque structure pointer for the data (a variant of the pimpl idiom).
There's another solution, which isn't exactly singleton pattern, but very related.
class FreeTypeManager
{
public:
FreeTypeManager();
~FreeTypeManager();
};
class SomeOtherClass
{
public:
SomeOtherClass(FreeTypeManager &m) : m(m) {}
private:
FreeTypeManager &m;
};
int main() {
FreeTypeManager m;
...
SomeOtherClass c(m);
}
The solution is to keep it ordinary c++ class, but then just instantiate it at the beginning of main(). This moves initialisation/destruction to a little different place. You'll want to pass references to FreeTypeManager to every class that wants to use it via constructor parameter.
Note that it is important that you use main() instead of some other function; otherwise you get scoping problems which require some thinking how to handle..
If I have two static variables in different compilation units, then their initialization order is not defined. This lesson is well learned.
The question I have: are all the static variables already allocated, when the first one is being initialized. In other words:
static A global_a; // in compilation unit 1
static B global_b; // in compilation unit 2
struct A {
A() { b_ptr = &global_b; }
B *b_ptr;
void f() { b_ptr->do_something(); }
}
int main() {
global_a.f();
}
Will b_ptr point to a valid piece of memory, where B is allocated and initialized at the time of the execution of the main function? On all the platforms?
Longer story:
The compilation unit 1 is Qt library.
The other one is my application. I have couple QObject derived classes, that I need to be able to instantiate by the class name string. For this I came up with a templated factory class:
class AbstractFactory {
public:
virtual QObject *create() = 0;
static QMap<const QMetaObject *, AbstractFactory *> m_Map;
}
QMap<const QMetaObject *, AbstractFactory *> AbstractFactory::m_Map; //in .cpp
template <class T>
class ConcreteFactory: public AbstractFactory {
public:
ConcreteFactory() { AbstractFactory::m_Map[&T::staticMetaObject] = this; }
QObject *create() { return new T(); }
}
#define FACTORY(TYPE) static ConcreteFactory < TYPE > m_Factory;
Then I add this macro on every QObject subclass definition:
class Subclass : public QObject {
Q_OBJECT;
FACTORY(Subclass);
}
Finally I can instantiate a class by the type name:
QObject *create(const QString &type) {
foreach (const QMetaObect *meta, AbstractFactory::m_Map.keys() {
if (meta->className() == type) {
return AbstractFactory::m_Map[meta]->create();
}
}
return 0;
}
So the class gets a static QMetaObject instance: Subclass::staticMetaObject from the Qt library - it is auto-generated in Q_OBJECT macro I think. And then the FACTORY macro creates a static ConcreteFactory< Subclass > instance. ConcreteFactory in its constructor tries to reference of Subclass::staticMetaObject.
And I was pretty happy with this implementation on linux (gcc), until I compiled it with Visual Studio 2008. For some reason AbstractFactory::m_Map was empty on the runtime, and the debugger would not break at the factory constructor.
So this is where the smell of static vars referencing other static vars is coming from.
How can I optimize this code to avoid all these traps?
Yes, the standard allows this.
There are a number of paragraphs in section [basic.life] which start out
Before the lifetime of an object has
started but after the storage which
the object will occupy has been
allocated or, after the lifetime of an
object has ended and before the
storage which the object occupied is
reused or released, any pointer that
refers to the storage location where
the object will be or was located may
be used but only in limited ways.
and there is a footnote which indicates that this specifically applies to your situation
For example, before the construction of a global object of non-POD class type
Short Answer: Its should work as you have coded it. See Ben Voigt Answer
Long Answer:
Do something like this:
Rather than let the compiler decide when globals are created, create them via static methods (with static function variables). This means that they will be deterministically created on first use (and destroyed in the reverse order of creation).
Even if one global uses another during its construction using this method gurantees that they will be created in the order required and thus be available for usage by the other (watch out for loops).
struct A
{
// Rather than an explicit global use
// a static method thus creation of the value is on first use
// and not at all if you don't want it.
static A& getGlobalA()
{
static A instance; // created on first use (destroyed on application exit)
// ^^^^^^ Note the use of static here.
return instance; // return a reference.
}
private:
A()
:b_ref(B::getGlobalB()) // Do the same for B
{} // If B has not been created it will be
// created by this call, thus guaranteeing
// it is available for use by this object
}
B& b_ref;
public:
void f() { b_ref.do_something(); }
};
int main() {
a::getGlobalA().f();
}
Though a word of warning.
Globals are an indication of bad design.
Globals that depend on other globals is another code smell (especially during construction/destruction).
Yes. All are located in .data section, that is allocated at once (and it's not heap).
Putting it another way: if you are able to take its address, then it's OK, because it surely won't change.
If B has a constructor, like A has, then the order that they are called is undefined. So your code won't work unless you are lucky. But if B doesn't require any code to initialise it, then your code will work. It's not implementation-defined.
Ah, but the idea that static variables are "not initialised" is quite wrong. They're always initialised, just not necessarily with your initialiser. In particular, all static variables are created with value zero before any other initialisation. For class objects, the members are zero. Therefore global_a.b_ptr above will always be a valid pointer, initially NULL and later &global_b. The effect of this is that use of non-pointers is unspecified, not undefined, in particular this code is well defined (in C):
// unit 1
int a = b + 1;
// unit 2
int b = a + 1;
main ... printf("%d\n", a + b); // 3 for sure
The zero initialisation guarantee is used with this pattern:
int get_x() {
static int init;
static int x;
if(init) return x;
else { x = some_calc(); init = 1; return x; }
}
which assures either a non-return due to infinite recursion, or, correctly initialised value.