0

This problem blocks me moving ahead. Please anyone kindly help me out.

My purpose is to implement a plugin factory which can create a plugin object by it's name(something like reflection, I guess?),

I define a namespace in header like:

// header file
namespace PluginFactory
{
  using MFP = std::function<IPlugin*()>;
  typedef std::map<std::string, MFP > mapType;

  extern mapType  g_ConstructMap;
  //extern std::map<std::string, int> mMap;

  extern IPlugin *CreateInstance(const std::string &className);

  template<typename T>
  IPlugin * createPlugin()
  {
    return new T;
  }

  template <typename T>
  extern void InsertMap(const std::string &pluginName)
  {
    g_ConstructMap.insert(std::make_pair(pluginName, &createPlugin<T>));
    //mMap.insert(std::make_pair(pluginName, 0));
  }
}
// source file
namespace  PluginFactory
{

  mapType  g_ConstructMap;
  std::map<std::string, int> mMap;

  IPlugin * CreateInstance(const std::string &className)
  {
    mapType::iterator it = g_ConstructMap.find(className);
    if(it == g_ConstructMap.end())
    {
      qWarning("Construct %s failed. Not find a construct in map.", className.c_str());
      return nullptr;
    }
    return it->second();
  }
}

and the register

template<typename T>
class PluginFactoryRegister
{
public:
  PluginFactoryRegister(const std::string &pluginName)
  {
    PluginFactory::InsertMap<T>(pluginName);
  }
};

Register a specific plugin class into this system, using the macro:

#define REGISTER_DEF_TYPE(NAME) \
    PluginFactoryRegister<NAME> NAME::regTbl(#NAME)

#define ADD_REGISTER_TABLE(NAME) \
    static PluginFactoryRegister<NAME> regTbl

Finnaly, call insert function in PluginFactoryRegister.

But, every time I run application, it complains Segment fault in exactly line:

namespace PluginFactory
{
...
   g_ConstructMap.insert(std::make_pair(pluginName, &createPlugin<T>));
...
}

[Update 1] I'm using two macros for adding specific plugin classes(more than two such subclass) into my 'reflection system', like:

// example_plugin.h
class ExamplePlugin: public IPlugin
{
 //...

 // reflection
 ADD_REGISTER_TABLE(ExamplePlugin);
}
// example_plugin.cpp

 // ...
 REGISTER_DEF_TYPE(ExamplePlugin);
 // ...

And in some place, I will call CreateInstance for create objects in a loop, like:

for(auto name : classnames)
{
  IPlugin * newPlugin = PluginFactory::CreateInstance(name);
  //...
}

Surely, I have tried many solutions, like define as class static map. That can barely help me.

  • 1
    Where is `g_ConstructMap` defined? And more specifically, is it defined in a different [translation unit](https://en.wikipedia.org/wiki/Translation_unit_(programming)) from the call that causes the crash? – Some programmer dude Oct 03 '20 at 11:25
  • You're probably (as some programmer dude suggests) running into the observed nullptr because of undefined initialization order, see https://stackoverflow.com/a/211307/3426025 for an explanation. – BeyelerStudios Oct 03 '20 at 11:29

2 Answers2

3

This looks like a classical static initialization order fiasco.

The solution is to register classes without touching global variables, possibly by putting them into functions and making them static.

Instead of mapType g_ConstructMap, do something like

mapType &g_ConstructMap()
{
    static mapType ret;
    return ret;
}

and so on.

HolyBlackCat
  • 78,603
  • 9
  • 131
  • 207
  • In fact, I have tried this and a pointer for static `mapType` object too. As I mentioned in my post, I want to implement a plugin factory(or a reflection system for creation a plugin object). And after I change my code into this way, segment fault problem is fixed, but another problem comes out: `find` fails to find a key which I've should pushed into the map. It seems that `g_ConstructMap()` return a different object of `mapType` in a different call which is so strange considering a static object. –  Oct 03 '20 at 12:26
  • @Mr.Frog Do you return by reference like I did? Can you confirm using breakpoints that you try to `find` the object *after* inserting it? A [mcve] would help. – HolyBlackCat Oct 03 '20 at 12:33
  • Yes, I do exactly what you did and all referred codes. I should post a mimimal example, but I find I can't, because it's hard to simplify related codes. I also updated my post on part of how I using this 'reflection system'. –  Oct 03 '20 at 13:09
  • 1
    OK, now segment fault is fixed as @HolyBlackCat method , but another problem shows up. I'll close this post and open another one. Thanks you all very much. –  Oct 04 '20 at 00:46
-1

I see a lot of pointers. Are you sure that you've properly initialised the map when you call insert on it?

I'd also suggest smart pointers.

Edward
  • 468
  • 4
  • 18