Object factory and Intel compiler

Discussion in 'C++' started by Ryan Mitchley, Aug 5, 2004.

  1. Hi all

    I have code for an object factory, heavily based on an article by Jim Hyslop
    (although I've made minor modifications). The factory was working fine using
    g++, but since switching to the Intel compiler it has stopped working. I
    think the singleton pattern static instance thing may be at the root of the
    problem, but I'm not sure. I had to add calls to instance() in regCreateFn,
    which gets the behaviour more in line with what I was expecting during
    static initialization (the objects all register with the same registry). I
    have tried playing with the MS compatibility options of the Intel compiler,
    with no success.

    The problem occurs when I make a call to manufacture a given object: a
    totally different instance of the factory and registry are used (I have
    checked this by printing out pointers).

    A typical call to the manufacture method would be:

    shared_ptr<CAngle3D> newB = boost::shared_polymorphic_cast<CAngle3D>
    (objectFactory<CBase>::instance().manufacture("CAngle3D"));

    This fails, since the objectFactory<CBase>::instance() returns a valid
    factory, but one with no items in the map of create functions (i.e. it is a
    different one to that used when registering the create functions in the
    static initalizers).

    In this example, the first section of the header for CAngle3D is as follows:
    class CAngle3D : public CBase
    {
    public:
    // Tell the Object Factory about this class
    //FACTORY_DECLARE_CLASS(CAngle3D
    static registerInFactory<CBase, CAngle3D> regClass;

    and the following is placed into the cpp for CAngle3D:
    // Register class with Object Factory
    //FACTORY_REGISTER_CLASS(CAngle3D)
    registerInFactory<CBase, CAngle3D> CAngle3D::regClass("CAngle3D");

    The complete CFactory.h listing is pasted at the end of this email. You will
    notice that there is a large amount of debugging info being output.

    The output of my program, when it starts up, is as follows: (Notice
    especially the memory addresses, that change when the program tries to
    manufacture a CAngle3D object)

    $ ./TestMathCore
    Constructor: objectFactory for class CBase
    Registering create function for "CAngle3D"
    Registry size = 1(0046FBD0)
    Registering clone function for "CAngle3D"
    registerInFactory: "CAngle3D"
    Constructor: objectFactory for class CBase
    Registering create function for "CFrequency"
    Registry size = 2(0046FBD0)
    Registering clone function for "CFrequency"
    registerInFactory: "CFrequency"
    Constructor: objectFactory for class CBase
    Registering create function for "CList"
    Registry size = 3(0046FBD0)
    Registering clone function for "CList"
    registerInFactory: "CList"
    Constructor: objectFactory for class CBase
    Registering create function for "CSortableList"
    Registry size = 4(0046FBD0)
    Registering clone function for "CSortableList"
    registerInFactory: "CSortableList"
    Constructor: objectFactory for class CBase
    Registering create function for "CCollection"
    Registry size = 5(0046FBD0)
    Registering clone function for "CCollection"
    registerInFactory: "CCollection"
    Constructor: objectFactory for class CBase
    Registering create function for "CAngle"
    Registry size = 6(0046FBD0)
    Registering clone function for "CAngle"
    registerInFactory: "CAngle"
    Min resolution = 1, Max resolution = 1000000
    Timer setting successful.
    The system clock interval is 10 ms.
    Adjustment disabled = 1
    MathCore Test App
    -----------------

    CAngle3D
    Constructor: objectFactory for class CBase
    Registry size = 0(0046FB04)
    Contents of Object Factory warehouse:

    Trying to manufacture "CAngle3D"
    Object Factory 0046FB04: 0 items
    objectFactory: Don't know how to manufacture that object type.
    Ensure that FACTORY_REGISTER_CLASS is used.

    I would *really* appreciate some help! Sorry for the hugely long post . . .

    Ryan


    // CFactory.h
    // object abstract factory template.
    // Copyright 2001, Jim Hyslop.
    // This file may be freely used, modified and distributed, provided that
    // the accompanying copyright notice remains intact.
    //
    // The object abstract factory template is an implementation of the
    // Abstract Class Factory pattern, as a template (see "Design Patterns:
    // Elements of Reusable Object-Oriented Software", E. Gamma, R. Helm,
    // R. Johnson, J. Vlissides, Addison Wesley [1995] )
    //
    // To use the template, you need to provide a base class and (optionally)
    // a key class. The base class must provide a unique identifier
    //
    // The key class must be able to be used as a key in a std::map, i.e. it
    must
    // - implement copy and assignment semantics
    // - provide bool operator< () const;
    // Default is std::string.
    //
    // Steps to using the factory:
    // 1 - Create the base class and its derivatives
    // 2 - Register each class in the factory by instantiating a
    // registerInFactory<> template class - do this in one file only (the
    // class implementation file is the perfect place for this)
    // 3 - create the object by calling create() and passing it the same
    // value used when you instantiated the registerInFactory object.
    // For example:
    // base header:
    // class Base { /* whatever (don't forget the virtual dtor! */ };
    //
    // base implementation:
    // registerInFactory<Base, Base, std::string> registerBase("Base");
    //
    // derived header:
    // class Derived : public Base { /* whatever */ };
    //
    // derived implementation:
    // registerInFactory<Base, Derived, std::string> registerDer("Derived");
    //
    // code that instantiates the classes:
    // std::auto_ptr<Base> newBase =
    objectFactory<Base>::instance().create("Base");
    // std::auto_ptr<Base> newDerived =
    objectFactory<Base>::instance().create("Derived");
    //
    // New derivatives can be added without affecting the existing code.

    #ifndef FACTORY_HEADER_DEFINED
    #define FACTORY_HEADER_DEFINED

    #include <boost/shared_ptr.hpp>

    using boost::shared_ptr;

    //#pragma warning(disable: 4275)
    //#pragma warning(disable: 4786)

    // Macro to simplify registration with the Object Factory and creation of a
    Clone function
    // To be used in the class declaration in the header file (.h) for the new
    class
    #define FACTORY_DECLARE_CLASS(_cNewClass) \
    static registerInFactory<CBase,_cNewClass>regClass;\
    virtual shared_ptr<CBase>Clone()\
    {return shared_ptr<CBase>(new _cNewClass(*this));}

    // Macro to simplify implementation of the registration function
    // To be used in the class implementation (.cpp) file for the new class
    #define FACTORY_REGISTER_CLASS(_cNewClass) \
    registerInFactory<CBase, _cNewClass> _cNewClass::regClass(#_cNewClass);

    // The abstract factory itself.
    // Implemented using the Singleton pattern

    template <class manufacturedObj>
    class objectFactory
    {
    public:
    // a BASE_CREATE_FN is a function that takes no parameters
    // and returns a pointer to a manufactuedObj. Note that
    // we use no parameters, but you could add them
    // easily enough to allow overloaded ctors, e.g.:
    typedef manufacturedObj* (*BASE_CREATE_FN)();

    typedef manufacturedObj* (*BASE_CLONE_FN)(manufacturedObj*);

    int iTest;
    // FN_REGISTRY is the registry of all the BASE_CREATE_FN
    // pointers registered. Functions are registered using the
    // regCreateFn member function (see below).
    typedef map<string, BASE_CREATE_FN> FN_REGISTRY;
    FN_REGISTRY registry;

    typedef map<string, BASE_CLONE_FN> FN_CLONE_REGISTRY;
    FN_CLONE_REGISTRY CloneRegistry;

    // Singleton implementation - private ctor & copying, with
    // no implementation on the copying.
    objectFactory();
    objectFactory(const objectFactory&); // Not implemented
    objectFactory &operator=(const objectFactory&); // Not implemented
    public:
    // Singleton access.
    static objectFactory &instance();

    // Method to register the class ID key, and a pointer to
    // the function that creates the class.
    void regCreateFn(const string & strClassID, BASE_CREATE_FN);

    // Method to register the class ID key, and a pointer to
    // the function that clones
    void regCloneFn(const string & strClassID, BASE_CLONE_FN);

    // Create a new class of the type specified by className.
    // manufacturedObj* manufacture(const std::string & className) const;
    shared_ptr<manufacturedObj> manufacture(const std::string & className)
    const;

    shared_ptr<manufacturedObj> clone(shared_ptr<manufacturedObj> pToClone)
    const;

    // Create a new class of the type specified by className.
    shared_ptr<manufacturedObj> assemble(list<string> &is,
    list<string>::const_iterator& i) const;
    };

    ////////////////////////////////////////////////////////////////////////
    // Implementation details.

    template <class manufacturedObj>
    objectFactory<manufacturedObj>::eek:bjectFactory()
    {
    cout << "Constructor: objectFactory for " << typeid(manufacturedObj).name()
    << endl;
    }

    template <class manufacturedObj>
    objectFactory<manufacturedObj> & objectFactory<manufacturedObj>::instance()
    {
    // Note that this is not thread-safe!
    static objectFactory theInstance;
    return theInstance;
    }

    // Register the creation function. This simply associates the classIDKey
    // with the function used to create the class. The return value is a dummy
    // value, which is used to allow static initialization of the registry.
    // See example implementations in base.cpp and derived.cpp
    template <class manufacturedObj>
    void objectFactory<manufacturedObj>::regCreateFn(const string & strClassID,
    BASE_CREATE_FN func)
    {
    cout << "Registering create function for \"" << strClassID << "\"" << endl;
    instance().registry[strClassID] = func;
    cout << "Registry size = " << instance().registry.size() << "(" <<
    &(instance().registry) << ")" << endl;
    }

    template <class manufacturedObj>
    void objectFactory<manufacturedObj>::regCloneFn(const string & strClassID,
    BASE_CLONE_FN func)
    {
    cout << "Registering clone function for \"" << strClassID << "\"" << endl;
    instance().CloneRegistry[strClassID]=func;
    }

    template <class manufacturedObj>
    shared_ptr<manufacturedObj>
    objectFactory<manufacturedObj>::manufacture(const std::string & className)
    const
    {
    cout << "Registry size = " << instance().registry.size() << "(" <<
    &(instance().registry) << ")" << endl;
    shared_ptr<manufacturedObj> manufactured;
    cout << "Contents of Object Factory warehouse:" << endl;
    typename FN_REGISTRY::const_iterator regIter = instance().registry.begin();
    while (regIter != instance().registry.end())
    cout << regIter->first << endl;
    cout << endl;

    typename FN_REGISTRY::const_iterator regEntry =
    instance().registry.find(className);
    cout << "Trying to manufacture \"" << className << "\"" << endl;
    cout << "Object Factory " << &(instance().registry) << ": " <<
    instance().registry.size() << " items" << endl;
    if (regEntry != instance().registry.end())
    manufactured.reset((*regEntry).second());
    else
    cout << "objectFactory: Don't know how to manufacture that object
    type.\nEnsure that FACTORY_REGISTER_CLASS is used." << endl;
    return manufactured;
    }

    // Clone an object using the class name of the cloned object
    template <class manufacturedObj>
    shared_ptr<manufacturedObj>
    objectFactory<manufacturedObj>::clone(shared_ptr<manufacturedObj> pToClone)
    const
    {
    cout << "clone(shared_ptr<manufacturedObj> pToClone) const" << endl;
    shared_ptr<manufacturedObj> manufactured;
    typename FN_CLONE_REGISTRY::const_iterator
    regEntry=CloneRegistry.find(pToClone->ClassName());
    if (regEntry != CloneRegistry.end())
    manufactured =
    shared_ptr<manufacturedObj>((*regEntry).second(pToClone.get()));
    else
    cout << "objectFactory: Don't know how to clone that object type.\nEnsure
    that FACTORY_REGISTER_CLASS is used." << endl;
    return manufactured;
    }

    // Assemble a new manufacturedObj using the list of string tokens and
    iterator supplied
    template <class manufacturedObj>
    shared_ptr<manufacturedObj>
    objectFactory<manufacturedObj>::assemble(list<std::string> &is,
    list<string>::const_iterator& i) const
    {
    cout << "assemble" << endl;
    string strObjType, strObjName;
    list<string>::const_iterator start = i;
    while ((i != is.end()) && ((*i).find("XSIL") == string::npos)) i++;
    // Read back the object name, if it is present
    while ((i != is.end()) && ((*i).find("Type") == string::npos)) i++;
    while ((i != is.end()) && ((*i).find("=") == string::npos)) i++;
    i++; strObjType = *i;
    shared_ptr<manufacturedObj> ret;
    typename FN_REGISTRY::const_iterator regEntry=registry.find(strObjType);
    if (regEntry != registry.end())
    ret.reset((*regEntry).second());
    i = start;
    ret->XML_Read(is, i);
    return ret;
    }

    // ************************************************************
    // Helper template to make registration painless and simple
    // ************************************************************
    template <class ancestorType,
    class manufacturedObj>
    class registerInFactory
    {
    public:
    static ancestorType* createInstance()
    {
    cout << "createInstance()" << endl;
    return (ancestorType*)(new manufacturedObj);
    }
    static ancestorType* cloneInstance(ancestorType * pObjToClone)
    {
    cout << "cloneInstance(ancestorType * pObjToClone)" << endl;
    manufacturedObj * pDerivedToClone = new manufacturedObj;
    *pDerivedToClone = *((manufacturedObj*)pObjToClone);
    // pDerivedToClone = (manufacturedObj*) pObjToClone;
    // cout << "Cloning " << pObjToClone->GetID() << endl;
    // return (ancestorType*)(new
    manufacturedObj(*((manufacturedObj*)pObjToClone)));
    return (ancestorType*)pDerivedToClone;
    }
    registerInFactory(const string id)
    {
    m_strClassName.assign(id);
    objectFactory<ancestorType>::instance().regCreateFn(m_strClassName,
    createInstance);
    objectFactory<ancestorType>::instance().regCloneFn(m_strClassName,
    cloneInstance);
    cout << "registerInFactory: \"" << m_strClassName << "\"" << endl;
    }
    protected:
    string m_strClassName;
    };

    #endif
     
    Ryan Mitchley, Aug 5, 2004
    #1
    1. Advertising

  2. Ryan Mitchley wrote:
    > Hi all
    >
    > I have code for an object factory, heavily based on an article by Jim Hyslop
    > (although I've made minor modifications). The factory was working fine using
    > g++, but since switching to the Intel compiler it has stopped working. I
    > think the singleton pattern static instance thing may be at the root of the
    > problem, but I'm not sure. I had to add calls to instance() in regCreateFn,
    > which gets the behaviour more in line with what I was expecting during
    > static initialization (the objects all register with the same registry). I
    > have tried playing with the MS compatibility options of the Intel compiler,
    > with no success.


    I have no idea, but creating singleton instances of factory registries
    is a tricky thing to do when messing with DLL's and template instances
    all around.

    May I suggest an alternative ? I released the Austria C++ library a few
    weeks ago that does implement a generic factory mechanism and it does
    deal with DLL/DSO hell. I have not tested it with the intel compiler.

    This is an example taken from the Austria test case.


    class Interface
    {

    public:

    virtual const char * Thingy() = 0;
    virtual const char * Thingy1() = 0;
    virtual const char * Thingy2() = 0;

    bool * mark_del;

    Interface()
    : mark_del( 0 )
    {
    }

    virtual ~Interface()
    {
    if ( mark_del )
    {
    * mark_del = true;
    }
    }

    void MarkPtr( bool * i_mark_del )
    {
    mark_del = i_mark_del;
    }

    virtual int ContructParamCount() = 0;

    };


    class Implementor
    : public Interface
    {

    public:

    virtual const char * Thingy()
    {
    return m_str;
    }

    virtual const char * Thingy1()
    {
    return m_str2;
    }

    virtual const char * Thingy2()
    {
    return m_str3;
    }

    Implementor( const char * str, const char * str2, const char * str3 )
    : m_str( str ),
    m_str2( str2 ),
    m_str3( str3 ),
    contruction_parameter_count( 3 )
    {
    }

    Implementor( const char * str, const char * str2 )
    : m_str( str ),
    m_str2( str2 ),
    contruction_parameter_count( 2 )
    {
    }

    Implementor( const char * str )
    : m_str( str ),
    contruction_parameter_count( 1 )
    {
    }

    Implementor()
    : m_str( "Empty" ),
    contruction_parameter_count( 0 )
    {
    }

    virtual int ContructParamCount()
    {
    return contruction_parameter_count;
    }

    int contruction_parameter_count;

    const char * m_str;
    const char * m_str2;
    const char * m_str3;
    };


    AT_MakeFactory1P( "ImplementorKEY", Implementor, Interface, DKy, const
    char * );
    AT_MakeFactory2P( "ImplementorKEY", Implementor, Interface, DKy, const
    char *, const char * );
    AT_MakeFactory3P( "ImplementorKEY", Implementor, Interface, DKy, const
    char *, const char *, const char * );

    AT_MakeFactory0P( "ImplementorKEY", Implementor, Interface, DKy );


    http://austria.sourceforge.net
    http://austria.sourceforge.net/dox/html/at__factory_8h-source.html

    The build system may not work for you, however the Austria build is
    fairly easy to configure.
     
    Gianni Mariani, Aug 5, 2004
    #2
    1. Advertising

  3. Ryan Mitchley wrote:

    > Hi all
    >
    > I have code for an object factory, heavily based on an article by Jim
    > Hyslop (although I've made minor modifications). The factory was
    > working fine using g++, but since switching to the Intel compiler it
    > has stopped working. I think the singleton pattern static instance
    > thing may be at the root of the problem,


    This could be a platform dependent problem. Can give more details?

    => What's the OS?
    => are the factories registered/used in a dll/dso?
    => if so, how do link to the dll/dso? Directly, through an import
    library or do you use something like LoadLibrary/dlopen?
    => What version did the g++ compiler have that used to work and what
    version of Intel's compiler are you trying to use now?

    Marco
     
    Marco Manfredini, Aug 5, 2004
    #3
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Medi Montaseri
    Replies:
    17
    Views:
    876
    Medi Montaseri
    Sep 3, 2003
  2. Faheem Mitha
    Replies:
    2
    Views:
    674
    Faheem Mitha
    Aug 26, 2006
  3. C#
    Replies:
    4
    Views:
    411
  4. whatnext
    Replies:
    9
    Views:
    421
  5. Kazik�
    Replies:
    4
    Views:
    1,335
    Jonathan Lee
    Jul 6, 2009
Loading...

Share This Page