3
\$\begingroup\$

My goal was to write a factory that the code did not have to be edited. Thus I am registering my factory functions into a singleton factory. I am going to be using this code in Apache thrift server RPC system. I want to make the factory thread-safe.

#include <string>
#include <iostream>
#include <stdexcept>
#include <map>
#include <memory>

namespace configNM{

class config{
   public:

     config(const std::string & filename);
     config(){};

     std::string getConfFileName()const{return _confFilename;};
   private:
      std::string _confFilename;
   protected:

};

class configColumnHeaders:public config{
   private:
   static bool registered;
   configColumnHeaders(){};
   configColumnHeaders(const std::string & filename):config(filename){std::cout << "configColumnHeaders" << std::endl;};


   protected:

   public:
   static std::unique_ptr<config> create(std::string in){
      std::cout << "creating configColumnHeaders" << std::endl;
      std::unique_ptr<configColumnHeaders> MyPtr(new configColumnHeaders(in));
      return std::move(MyPtr);
   };
};

class configColumnsNoHeaders:public config{
   private:

   configColumnsNoHeaders(){};
   configColumnsNoHeaders(const std::string & filename):config(filename){std::cout << "configColumnsNoHeaders" << std::endl;};
   static bool registered;
   protected:

   public:

   static std::unique_ptr<config> create(std::string in){
      std::unique_ptr<configColumnsNoHeaders> MyPtr(new configColumnsNoHeaders(in));
      return std::move(MyPtr);
   };

};

class configFixed:public config{
   private:
   configFixed(){};
   configFixed(const std::string & filename):config(filename){std::cout << "configFixed" << std::endl;};
   static bool registered;
   protected:
   static std::unique_ptr<config> create(std::string in){
      std::unique_ptr<configFixed> MyPtr(new configFixed(in));
      return std::move(MyPtr);
   };

   public:
};

class configFactory{
public:
  typedef std::unique_ptr<config> (*configCreateFunction)(std::string);
  std::map<std::string,configCreateFunction> registeredConfigs;

  static configFactory* instance(){
          static configFactory factory;
         return &factory;
      }

  bool registerConfig(const std::string & name,std::unique_ptr<config> (createFunction)(std::string)){
   registeredConfigs.insert(std::make_pair(name,createFunction));
   return true;
  }
  std::unique_ptr<config> createConfig(const std::string& name, std::string filename)
  {
      return registeredConfigs[name](filename);
  }


};

}

using namespace configNM;
config::config(const std::string & filename){
   _confFilename=filename;
}

bool configColumnHeaders::registered = configFactory::instance()->registerConfig("column_headers", configColumnHeaders::create);
bool configColumnsNoHeaders::registered = configFactory::instance()->registerConfig("columns_no_headers", configColumnsNoHeaders::create);
bool configFixed::registered = configFactory::instance()->registerConfig("fixed", configFixed::create);


int main(void){
   config myConfig("columnHeaders.json");

   auto myPtr = configFactory::instance()->createConfig("column_headers","parameter");
   auto myPtr2 = configFactory::instance()->createConfig("columns_no_headers","parameter");
   auto myPtr3 = configFactory::instance()->createConfig("fixed","parameter");
   return 0;
}

I checked out SO and it looks like the best minimal singleton that is thread-safe for C++11 is:

class S
{
    public:
        static S& getInstance()
        {
            static S    instance; // Guaranteed to be destroyed.
                                  // Instantiated on first use.
            return instance;
        }
    private:
        S() {};                   // Constructor? (the {} brackets) are needed here.

        // C++ 03
        // ========
        // Dont forget to declare these two. You want to make sure they
        // are unacceptable otherwise you may accidentally get copies of
        // your singleton appearing.
        S(S const&);              // Don't Implement
        void operator=(S const&); // Don't implement

        // C++ 11
        // =======
        // We can use the better technique of deleting the methods
        // we don't want.
        S(S const&)               = delete;
        void operator=(S const&)  = delete;

};

Should I change to this? Is this good practice for a factory to register classes like this?

\$\endgroup\$
1
  • 1
    \$\begingroup\$ It appears that the only difference here is that the code in my second codeblock posted has deleted the copy constructor and equals operator method. \$\endgroup\$
    – user249806
    Commented Nov 11, 2015 at 12:44

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Browse other questions tagged or ask your own question.