SIGSEGV with std::map of pointers to template objects - c++

I need to keep a std::map of pointers to templated objects.
To get rid of templates, I use a common untemplated base class.
When running the code, I get a SIGSEGV signal.
Debugging shows that the problem arises with statement
data_[id] = s;
It could be a problem related to the order of initialization of the objects.
The code looks like this:
File shared_iface.h:
class shared_iface {
unsigned long int counter_;
};
File shared.h:
extern CommunicationHandler comm;
template <typename T>
class shared: private shared_iface {
public:
shared(): data_(nullptr), id_(0) {
comm.add(id_, this);
}
private:
T* data_;
unsigned long int id_;
};
File communication_handler.h:
class CommunicationHandler {
public:
inline void add(unsigned long int id, shared_iface* s) {
data_.add(id, s);
}
private:
Dictionary data_;
};
File communication_handler.cpp:
CommunicationHandler comm;
File dictionary.h:
class Dictionary {
public:
Dictionary() {
data_.clear();
}
void add(unsigned long int id, shared_iface* s) {
data_[id] = s;
}
private:
std::map<unsigned long int, shared_iface*> data_;
};
File main.cpp:
#include "shared.hpp"
shared<int> c;
int main ()
{
return 1;
}

It could be a problem related to the order of initialization of the objects.
A good guess. c is a static object of type shared<int>. The constructor ofshared<T> depends on the static object comm. c may very well be initialized before comm and you'll get undefined behaviour. comm could have been initialized first, you're lucky that your code didn't work.
This is known as static initialization order fiasco. The usual way to avoid the fiasco is Construct On First Use Idiom but in general, avoid static objects that depend on other static objects.

Related

How to define the size of an array that is a static member of a non instanciable class?

I'm writing a class I don't want to instantiate. All its members are static. This class represents a peripheral of a microcontroller. Since there is only one instance of that peripheral in the microcontroller doesn't make sense to me create instances of that class. The class only groups the data and functions of that peripheral.
One of the data members of the class is an array whose size the user of the class should define at compile time. If I could create objects of this class I know I could initialize consts in the initializer list of a constructor, but I really don't want to create instances of this class. Maybe I could use templates and set the array size as the template parameter, but I would need to use something like my_class<5>::do_something() for every member call. Is there a simpler way to solve this problem? I'd like to make my class something like this:
class my_class
{
private:
static const int _size;
static int _array[_size];
public:
static void array_size(int size) { _size = size; }
static void do_something() { /* .... */ }
};
Consider using class template parametrized with constexpr array size and then create an alias:
#include <array>
template <std::size_t Size>
class my_class_impl {
private:
static constexpr std::size_t size = Size;
static std::array<int, Size> arr;
public:
static void do_something() { /* .... */ }
};
template <std::size_t Size>
std::array<int, Size> my_class_impl<Size>::arr;
using my_class = my_class_impl<10>;
int main() {
my_class::do_something();
}
Your best bet is probably a good old define.
Here's how I'd structure this (using namespaces, as it's the idiomatic way to do static-only classes):
peripheral.h:
namespace peripheral {
void do_something();
}
peripheral.cpp:
#ifndef PERIPH_ARRAY_SIZE
# error "please define the size of array"
#endif
namespace {
int _array[PERIPH_ARRAY_SIZE];
}
namespace peripheral {
void do_something() {...}
}
One way to allow the user to set the size, would be to change the array to a vector. Since it's private you control how it's used. A simple bool will restrict whether it's sized once and making sure it does get sized:
class my_class
{
private:
static const int _size = 10;
static vector<int> _array;
static bool arraySized;
public:
static void array_size( int size = _size )
{
if ( !arraySized )
{
_array = vector<int>( size );
arraySized = true;
}
}
static void do_something()
{
if ( arraySized )
{
/* .... */
}
}
};
While not at compile time, it does have the same effect.
A couple of other things to think about, using a template based approach can allow more than 1 instance of that class to be created. Which can break the singularity principle that you seem to want
using my_class = my_class_impl<10>;
using my_class2 = my_class_impl<20>;
int main() {
my_class::do_something();
my_class2::do_something();
}
The other thing is that the newest Atmel framework does include headers for vectors. The information you referenced must be out of date.
Your main requirement is that the array size is set at compile time. This is more C-ish, something you'd generally avoid when writing C++, but in your case, it might make more sense to use macros, such as
#define ARRAY_SIZE
... somewhere in your class ...
static int array_name[ARRAY_SIZE];

Can I initialize a static const member at run-time in C++?

Is it possible to initialize a static const member of my class during run-time? This variable is a constant throughout my program but I want to send it as a command-line argument.
//A.h
class A {
public:
static const int T;
};
//in main method
int main(int argc,char** argv)
{
//how can I do something like
A::T = atoi(argv[1]);
}
If this cannot be done, what is the type of variable I should use? I need to initialize it at run-time as well as preserve the constant property.
You cannot rely on data produced after your main has started for initialization of static variables, because static initialization in the translation unit of main happens before main gets control, and static initialization in other translation units may happen before or after static initialization of main translation unit in unspecified order.
However, you can initialize a hidden non-const variable, and provide a const reference to it, like this:
struct A {
public:
// Expose T as a const reference to int
static const int& T;
};
//in main.cpp
// Make a hidden variable for the actual value
static int actualT;
// Initialize A::T to reference the hidden variable
const int& A::T(actualT);
int main(int argc,char** argv) {
// Set the hidden variable
actualT = atoi(argv[1]);
// Now the publicly visible variable A::T has the correct value
cout << A::T << endl;
}
Demo.
I am sorry to disagree with the comments and answers saying that it is not possible for a static const symbol to be initialized at program startup rather than at compile time.
Actually this IS possible, and I used it many times, BUT I initialize it from a configuration file. Something like:
// GetConfig is a function that fetches values from a configuration file
const int Param1 = GetConfig("Param1");
const int MyClass::Member1 = GetConfig("MyClass.Member1");
As you see, these static consts are not necessarily known at compile time. They can be set from the environment, such as a config file.
On the other hand, setting them from argv[], seems very difficult, if ever feasible, because when main() starts, static symbols are already initialized.
No, you cannot do that.
If this cannot be done what is the type of variable I should use ?
You can use a non-const member.
class A
{
public:
static int T;
};
int A::T;
Another option is to make T a private member, make main a friend so only it can modify the value, and then expose the member through a function.
#include <cstdlib>
class A
{
public:
static int getT() { return T; }
private:
static int T;
friend int main(int argc, char** argv);
};
int A::T;
int main(int argc, char** argv)
{
A::T = std::atoi(argv[1]);
return 0;
}
Not only you can't, you should not try doing this by messing with const_cast. Static const members have a very high chance of ending up in read-only segment, and any attempt to modify them will cause program to crash.
Typically you will have more than one configuration value. So put them in a struct, and the normal global access to it is const.
const config* Config;
...
main (int argc, char* argv [])
{
Config= new config (argc, argv);
...
}
You can get fancier and have a global function to return config, so normal code can't even change the pointer, but it is harder to do that by accident.
A header file exposes get_config () for all to use, but the way to set it is only known to the code that's meant to do so.
No, since you defined the variable as static and const, you cannot change its value.
You will have to set its value in the definition itself, or through a constructor called when you create an object of class A.
Method #1: Initialize a hidden non-const variable, and provide a const reference to it (as shown by dasblinkenlight):
class A {
public:
static const int &T;
};
static int dummy = 0;
const int &A::T = dummy;
int main() {
dummy = 10;
std::cout << A::T << std::endl;
}
Live Demo
Method #2: Use a non const static member (as shown by R Sahu):
class A {
public:
static int T;
};
int A::T = 0;
int main() {
A::T = 10;
}
Live Demo
Method #3: Declare a hidden non-const variable as a private static member of your class and provide a static member const reference to interface it. Define a friend function as inititalizer:
class A {
friend void foo(int);
static int dummy;
public:
static const int &T;
};
const int &A::T = A::dummy;
int A::dummy = 0;
void foo(int val) { A::dummy = val; }
int main() {
foo(10);
std::cout << A::T << std::endl;
}
Live Demo
Method #4: Declare a hidden non-const variable as a private static member of your class and provide a static member const reference to interface it. Define a static member function as inititalizer:
class A {
static int dummy;
public:
static const int &T;
static void foo(int val) { A::dummy = val; }
};
const int &A::T = A::dummy;
int A::dummy = 0;
int main() {
A::foo(10);
std::cout << A::T << std::endl;
}
Live Demo
Bonus:
If you want to initialize only once you can change the helper function to:
static void foo(int val) {
static bool init = true;
if(init) A::dummy = val;
init = false;
}
Live Demo
Having been facing the same problem myself lately I found #A.S.H 's answer to be the closest to perfect but the fact that the variables have to be initialized so early can cause some problems:
Can't use data sources that aren't available yet, such as argc and argv as per the question.
Some dependencies might not be initialized yet. For example, many a GUI framework does not allow creating textboxes that early on yet. This is a problem because we might want to display a error textbox if loading the configuration file fails to inform the user.
So I came up with the following:
template <class T>
class StaticConfig
{
public:
StaticConfig()
{
if (!mIsInitialised)
{
throw std::runtime_error("Tried to construct uninitialised StaticConfig!");
}
}
const T*
operator -> () const
{
return &mConfig;
}
private:
friend class ConfigHandler;
StaticConfig(const T& config)
{
mConfig = config;
mIsInitialised = true;
}
static T mConfig;
static bool mIsInitialised;
};
template <class T>
T StaticConfig<T>::mConfig;
template <class T>
bool StaticConfig<T>::mIsInitialised = false;
We make our data static but non-const so we don't have to initialize it immediately and can assign the correct values to it at a more opportune time. Read only access is given trough a overload of operator -> The default constructor checks if a StaticConfig of this type has already been loaded with valid data and throws if it is not. This should never happen in practice but serves as a debugging aid. A private constructor allows loading the type with valid data. A ConfigHandler class, responsible for loading the data, is made a friend so it can access the private constructor.
A ConfigHandler instance can be briefly created at an opportune time when all the dependencies are available to initialize all the StaticConfig types. Once done, the ConfigHandler instance can be discarded. After that, a class can simply include the appropriate type of StaticConfig as a member and read-only access the data with minimal intrusion.
Online demonstration.
N - O
The semantics of what is being required are all wrong, and you shouldn't use a static-const for that.
A static is an object or integral type which has static storage duration and internal linkage.
A const is an object that does not change its value throughout application's lifetime, any attempt to change it results in UD . ( the overwhelming majority of such cases is a pretty well defined crash )
As a result of this question dangerous workarounds have been proposed to mimic the implied behavior. In most of examples a static-const-reference is given a somehow hidden static which is assignable at runtime, e.g. this.
Apart from the difficulties in maintaining such code, the problem remains that declared semantics are not actually enforced.
For example in keeping the value const throughout the application runtime can be hacked by doing const_cast<int &>(A::T) = 42 , which is perfectly valid, perfectly define code since the referenced type is not const.
What is being sought after here is an class that permits to be initialized only once throughout the application, has internal linkage, and the lifetime of the application.
So just do a template class that does that:
template<typename V> class fixation
{
bool init = true;
V val;
public:
fixation(V const & v) : init(true), val(v) {}
fixation & operator=( fixation arg)
{
if(init )
{
this->val = arg.val;
}
this->init = false;
return *this;
}
V get()
{
return val;
}
};
struct A
{
static fixation<int> T;
};
How to handle the case that it is called a second time, that is an implementation decision. In this example the value is totally ignored. Others may prefer to throw an exception, do an assertion, ... etc.
There is a trick, but you should probably avoid it! Here's a bare bones example to illustrate the principle:
int const& foo(int i) {
static const int j = (i == 0 ? throw 0 : i);
return j;
}
int main() {
try {
int x = foo(0); // oops, we throw
} catch(...) {}
int x = foo(1); // initialized..
int y = foo(0); // still works..
}
Careful!
Use a Singleton Pattern here.
have a data member which you'd like to initialize at run time in the singleton class. One a single instance is created and the data member is properly initialized, there would be no further risk of overwriting it and altering it.
Singleton would preserve the singularity of your data.
Hope this helps.

Error logging in c++

I implemented a very simple (error) logger class. It looks like this:
#pragma once
#include <string>
extern const char* LOG_DEFAULT_TEXT = "<LOG>\n\n";
class Log
{
public:
Log() : _logs(0), _log(LOG_DEFAULT_TEXT) {};
void add(const char *str, bool nl=true);
void clear();
const char* get() const { return _log.c_str(); }
int getNumLogs() const { return _logs; }
private:
std::string _log;
int _logs;
};
Now my question is, say I have this Main class, that contains all the other objects that my program may contain, and also this Log class.
Obviously I would want these "other objects" in my Main class to be able to use the Log object in Main, so the easy solution would be to pass pointers to every class' constructor so that it could use the Log object.
I'm talking about something like this:
//Main.h
...
#include "Log.h"
class Main() {
public:
...
private:
Log _log;
ImportantObject1(&_log); //pass a pointer to _log
ImportantObject2(&_log); //..same
};
This solution seems too clumsy, so I'm asking if there are different approaches for what I want to accomplish, which is error logging.
That's one of the rare cases a singleton makes sense:
class Log
{
public:
void add(const char *str, bool nl=true);
void clear();
const char* get() const { return _log.c_str(); }
int getNumLogs() const { return _logs; }
static Log& instance() {
static Log theInstance;
return theInstance;
}
private:
Log() : _logs(0), _log(LOG_DEFAULT_TEXT) {};
std::string _log;
int _logs;
};
This way you can use it elsewhere just accessing
Log::instance().add("Blah Blah",true);
Another approach to address the requirement...
Use functions in a suitable namespace instead of a singleton.
Log.h:
namespace Log
{
void add(const char *str, bool nl=true);
void clear();
const char* get();
int getNumLogs();
}
Log.cpp:
namespace detail
{
// This is almost same as the class from OP's post.
struct LogImpl
{
LogImpl(std::string const& log) : _logs(0), _log(log) {};
void add(const char *str, bool nl=true);
void clear();
const char* get() const { return _log.c_str(); }
int getNumLogs() const { return _logs; }
std::string _log;
int _logs;
};
}
namespace Log
{
// This mimics the singleton implementation...
// Create only one instance of LogImpl.
static detail::LogImpl impl("<LOG>\n\n");
void add(const char *str, bool nl)
{
impl.add(str, nl);
}
void clear()
{
impl.clear();
}
const char* get()
{
return impl.get();
}
int getNumLogs()
{
return impl.getNumLogs();
}
}
namespace Log
{
void add(const char *str, bool nl=true);
void clear();
const char* get();
int getNumLogs();
}
Using functions in a namespace vs using a singleton
To support use of functions in a namespace requires bit more code.
However, it simplifies calling code.
Calling code can use
Log::add(...);
instead of
Log::instance()->add(...);
Another common pattern inherited from C would be a global object. Globals are generally frowned upon because they are the symptom of bad design. But it makes sense for a logger to be a global.
That means that the header for your class should contain :
extern Log log;
and the cpp
#include <log.h>
...
Log log; // unique definition for the global Log
Then in any module using the log :
#include <log.h>
...
log.add(...);
The caveat here that there will be static initialization of Log log. And C++ is not always very nice with order of static initialization : ... Otherwise, the initialization of a variable is indeterminately sequenced with respect to the initialization of
a variable defined in a different translation unit.. The only foolproof way is to ensure that :
Log construction does not depend on any other statically initialized variable needing a constructor phase in another translation unit - it includes std::string but hopefully not const char *
the global variable is used once before any multithreading starts
If in doubt, use the singleton pattern suggested by πάντα ῥεῖ

Store pointers to member function in the map

I'd like to map string to an instance member functions, and store each mapping in the map.
What is the clean way of doing something like that?
class MyClass
{
//........
virtual double GetX();
virtual double GetSomethingElse();
virtual double GetT();
virtual double GetRR();
//........
};
class Processor
{
private:
typedef double (MyClass::*MemFuncGetter)();
static map<std::string, MemFuncGetter> descrToFuncMap;
public:
static void Initialize();
void Process(Myclass m, string);
};
void Processor::Initialize()
{
descrToFuncMap["X"]=&MyClass::GetX;
descrToFuncMap["SomethingElse"]=&MyClass::GetSomethingElse;
descrToFuncMap["RR"]=&MyClass::GetRR;
descrToFuncMap["T"]=&MyClass::GetT;
};
void Processor::Process(MyClass ms, const std::string& key)
{
map<std::string, Getter>::iterator found=descrToFuncMap.find(key);
if(found!=descrToFuncMap.end())
{
MemFuncGetter memFunc=found->second;
double dResult=(ms).*memFunc();
std::cout<<"Command="<<key<<", and result="<<result<<std::end;
}
}
let me know if you see a problem with this approach and what are common idioms for that?
Perhaps, I should use if-else-if statement chain, given that I have a limited number of member functions, instead of a confusing map of func pointers
BTW, I found some of the useful info here in the c++-faq-lite
Looks fine to me, but for the fact that descrToFuncMap needs to be declared static if you intend to initialise it from inside the static function Initialize().
If you want to make sure that Initialize() gets called, and gets called just once, you can use the Singleton pattern. Basically, if you aren't doing multithreading, that just means wrapping descrToFuncMap inside its own class (called say FuncMap) with a private constructor that calls Initialize(). Then you add a static local variable of type FuncMap to Processor::Process() -- because the variable is static, it persists and is only initialised once.
Example code (I now realise that friend isn't really necessary here):
class Processor {
private:
typedef double (MyClass::*MemFuncGetter)();
class FuncMap {
public:
FuncMap() {
descrToFuncMap["X"]=&MyClass::GetX;
descrToFuncMap["SomethingElse"]=&MyClass::GetSomethingElse;
descrToFuncMap["RR"]=&MyClass::GetRR;
descrToFuncMap["T"]=&MyClass::GetT;
}
// Of course you could encapsulate this, but its hardly worth
// the bother since the whole class is private anyway.
map<std::string, MemFuncGetter> descrToFuncMap;
};
public:
void Process(Myclass m, string);
};
void Processor::Process(MyClass ms, const std::string& key) {
static FuncMap fm; // Only gets initialised on first call
map<std::string, Getter>::iterator found=fm.descrToFuncMap.find(key);
if(found!=fm.descrToFuncMap.end()) {
MemFuncGetter memFunc=found->second;
double dResult=(ms).*memFunc();
std::cout<<"Command="<<key<<", and result="<<result<<std::end;
}
}
This is not the "true" Singleton pattern as different functions could create their own, separate instances of FuncMap, but it's enough for what you need. For "true" Singleton, you would declare FuncMap's constructor private and add a static method, say getInstance(), which defined the one-and-only instance as a static variable and returned a reference to that. Processor::Process() would then use this with
FuncMap& fm = FuncMap::getInstance();
I'd change
void Processor::Process(MyClass ms, std::string key)
to
void Processor::Process(const MyClass& ms, const std::string& key)
Don't see any bad side effect for now. Probably with boost::function as a map value it will be easier in the future.
Avoid using 'virtual' if you are using maps of function pointers. In this context, using 'virtual' keyword will not help much. For example
descrToFuncMap["X"]=&MyClass::GetX;
will always call 'MyClass::GetX' function even if GetX is overridden by the derived class of MyClass.
Usually you won't have large number of functions in class, rather than using map you can create simple struct array and use a for loop. If the number of functions are small, there won't be any big performance difference in map and array. Something similar to code below will work
class MyClass
{
//........
double GetX();
double GetSomethingElse();
double GetT();
double GetRR();
//........
};
typedef double (MyClass::*MemFuncGetter)();
struct FuncTable
{
const char* m_pFuncName;
MemFuncGetter m_pFuncPtr;
};
class Processor
{
public:
void Process(Myclass& m, string);
};
static FuncTable descrToFuncMap[]
{
{ "X", &MyClass::GetX},
{ "SomethingElse", &MyClass::GetSomethingElse },
{ "RR", &MyClass::GetRR},
{ "T", &MyClass::GetT}
};
void Processor::Process(MyClass& ms, const std::string& key)
{
int functablesize = sizeof(descrToFuncMap)/sizeof(descrToFuncMap[0])
for(int i=0; i< functablesize; ++i)
{
if( strcmp(key.c_str(), descrToFuncMap[i].m_pFuncName)==0)
{
MemFuncGetter memFunc=descrToFuncMap[i].m_pFuncPtr;
double dResult=(ms).*memFunc();
std::cout<<"Command="<<key<<"result="<<result<<std::end;
break;
}
}
}

Best way to for C++ types to self register in a list?

Suppose I have some per-class data: (AandB.h)
class A
{
public:
static Persister* getPersister();
}
class B
{
public:
static Persister* getPersister();
}
... and lots and lots more classes. And I want to do something like:
persistenceSystem::registerPersistableType( A::getPersister() );
persistenceSystem::registerPersistableType( B::getPersister() );
...
persistenceSystem::registerPersistableType( Z::getPersister() );
... for each class.
My question is: is there a way to automate building a list of per-type data so that I don't have to enumerate each type in a big chunk (as in the above example)?
For example, one way you might do this is: (AutoRegister.h)
struct AutoRegisterBase
{
virtual ~AutoRegisterBase() {}
virtual void registerPersist() = 0;
static AutoRegisterBase*& getHead()
{
static AutoRegisterBase* head= NULL;
return head;
}
AutoRegisterBase* next;
};
template <typename T>
struct AutoRegister : public AutoRegisterBase
{
AutoRegister() { next = getHead(); getHead() = this; }
virtual void registerPersist()
{
persistenceSystem::registerPersistableType( T::getPersister() );
}
};
and use this as follows: (AandB.cxx: )
static AutoRegister<A> auto_a;
static AutoRegister<B> auto_b;
Now, after my program starts, I can safely do: (main.cxx)
int main( int, char ** )
{
AutoRegisterBase* p = getHead();
while ( p )
{
p->registerPersist();
p = p->next;
}
...
}
to collect each piece of per-type data and register them all in a big list somewhere for devious later uses.
The problem with this approach is that requires me to add an AutoRegister object somewhere per type. (i.e. its not very automatic and is easy to forget to do). And what about template classes? What I'd really like is for the instantiation of a template class to somehow cause that class to get automatically registered in the list. If I could do this I would avoid having to have the user of the class (rather than the author) to remember to create a:
static AutoRegister< SomeClass<X1> > auto_X1;
static AutoRegister< SomeClass<X2> > auto_X2;
...
etc....
for each template class instantiation.
For FIW, I suspect there's no solution to this.
You can execute something before main once if a instantiation of a template is made. The trick is to put a static data member into a class template, and reference that from outside. The side effect that static data member triggers can be used to call the register function:
template<typename D>
struct automatic_register {
private:
struct exec_register {
exec_register() {
persistenceSystem::registerPersistableType(
D::getPersister()
);
}
};
// will force instantiation of definition of static member
template<exec_register&> struct ref_it { };
static exec_register register_object;
static ref_it<register_object> referrer;
};
template<typename D> typename automatic_register<D>::exec_register
automatic_register<D>::register_object;
Derive the class you want to be auto-registered from automatic_register<YourClass> . The register function will be called before main, when the declaration of referrer is instantiated (which happens when that class is derived from, which will implicitly instantiate that class from the template).
Having some test program (instead of the register function, a function do_it is called):
struct foo : automatic_register<foo> {
static void do_it() {
std::cout << " doit ";
}
};
int main() {
std::cout << " main ";
}
Yields this output (as expected):
doit main
Register each template at run-time in the constructor. Use a static variable per template to check if the type has already been registered. The following is a quickly hacked together example:
#include <iostream>
#include <vector>
using namespace std;
class Registerable {
static vector<Registerable *> registry_;
public:
static void registerFoo(Registerable *p)
{
registry_.push_back(p);
}
static void printAll()
{
for (vector<Registerable *>::iterator it = registry_.begin();
it != registry_.end(); ++it)
(*it)->print();
}
virtual void print() = 0;
};
vector<Registerable *> Registerable::registry_;
template <typename T>
class Foo : public Registerable {
static bool registered_;
public:
Foo()
{
if (!registered_) {
registerFoo(this);
registered_ = true;
}
}
void print()
{
cout << sizeof (T) << endl;
}
};
template <typename T> bool Foo<T>::registered_ = false;
int
main(int argc, char *argv[])
{
Foo<char> fooChar;
Foo<short> fooShort;
Foo<int> fooInt;
Registerable::printAll();
return 0;
}
It should output the size of each template parameter in the order the classes were instantiated:
1
2
4
This version removes the registration code from each constructor and puts it in a base class.
#include <iostream>
#include <vector>
using namespace std;
class Registerable {
static vector<Registerable *> registry_;
public:
static void registerFoo(Registerable *p)
{
registry_.push_back(p);
}
static void printAll()
{
for (vector<Registerable *>::iterator it = registry_.begin();
it != registry_.end(); ++it)
(*it)->print();
}
virtual void print() = 0;
};
vector<Registerable *> Registerable::registry_;
template <typename T>
class Registerer : public Registerable {
static bool registered_;
public:
Registerer(T *self)
{
if (!registered_) {
registerFoo(self);
registered_ = true;
}
}
};
template <typename T> bool Registerer<T>::registered_ = false;
template <typename T>
class Foo : public Registerer<Foo<T> > {
public:
Foo() : Registerer<Foo<T> >(this) { }
void print()
{
cout << sizeof (T) << endl;
}
};
int
main(int argc, char *argv[])
{
Foo<char> fooChar;
Foo<short> fooShort;
Foo<int> fooInt;
Registerable::printAll();
return 0;
}
I added an example of another non-template class using the registry. So, the final output would be:
foo: 1
foo: 2
foo: 4
bar
The Registerable solution is a neat idea, but has a couple of issues.
Ideally, I'd like to not add code to the constructor:
Because it relies on calling the constructor in order to register the type, it's a
little haphazard about what gets registered and what doesn't.
For things like persistence, I may never call the constructor of a particular type
before using the list, but I may need the type's data in the list in order to
know how to un-persist an object in a file.
There's runtime cost during the constructor call. I'd like to front load the time cost
and not pay the cost many times. If I had a vector of these objects and resized the
vector I'd pay the time-cost each time the copy constructor was called.
Use file-level static blocks to perform the different registrations
A static block? What's that?
A static block is a block of code (i.e. code between curly braces, which defines a scope) that gets executed sometime before main() runs. Java has this feature, and C++ has it too-
Whatch'a talkin' bout, Willis? C++ don't have no static blocks!
No, really, C++ has static blocks. You just need to, uh, shall we say, "expose" their existence.
Hmm. Curious. And how do the static blocks help my registration problem?
It's really very simple. Right after you define class A, you register it like so:
class A { /* ... whatever ... */ };
static_block {
persistenceSystem::registerPersistableType(A::getPersister());
}
There is one caveat, though: static blocks can be a part of the static initialization order fiasco together with any statically-initialized part of your persistence system; so you need to make sure it's ok for these static blocks to run before (most) other statics; and that it's ok for the different classes' Persister's to be registered in arbitrary order.