-1

Taking help from various sources, I managed to write a simple templates based factory pattern class where the factory doesn't depend on any of the derived classes. I uploaded the code here: https://github.com/piyushsoni/FactoryPattern . It might not be perfect but it works - though to my surprise only in this example. When I use this almost identically in our large actual codebase, it calls the constructor of the 'DerivedFactory' for only a few of the classes, and totally ignores for the other ones. It is only when I define a static function which can access the DerivedFactory object, and then actually call that function somewhere to assign that derived factory object to an lvalue (without there being a need) does it calls its constructor (whereas the way I create them in main.cpp should be sufficient). It looks like the compiler is doing some unneeded optimization here.

One difference can be that this sample project was tested in VC 15, while the actual codebase uses Intel Compiler with C++ 11 features enabled (which in turn uses MSVC11 on Windows and gcc on Linux). How can I fix that and make sure these simple static objects are created every time for both MSVC11 and GCC 4.8 onwards?

Edit: I wanted to avoid writing all code here to keep the question clean and putting the source code at one public location, but doing it here now on feedback (and to avoid getting it closed). I again want to write that this simple code is actually working, but almost identical code is not working when I put it in our commercial code which is compiled using Intel Compiler which is internally using MSVC11 on Windows. If you have any other questions, please ask them in comments and I'll try to answer, please don't try to close the question before letting me answer them. I have written the exact problem I'm facing above.

Here are the files:

ShapeFactory.h

#pragma once

#include <map>
using namespace std;

#include "Shape.h"

#define REGISTER_CLASS(objectClass) static DerivedFactory<objectClass> shape##objectClass(Type_ ## objectClass);

class Shape;
class ShapeFactory;
typedef map<ShapeType, ShapeFactory*> mapTypeShapeFactoryByType;

class ShapeFactory
{
private:
    mapTypeShapeFactoryByType mapShapeTypeByFactory;
protected:
    ShapeFactory() {}
    virtual Shape* Create() { return NULL; }
private:
    ShapeFactory(const ShapeFactory&);
public:
    virtual ~ShapeFactory() {}
    static ShapeFactory& GetShapeFactory();

    Shape* CreateShape(ShapeType type);

    virtual void DestroyShape(Shape* object) { delete object; object = nullptr; }
    void RegisterFactory(ShapeType type, ShapeFactory* factory);
};

template<typename ShapeClass>
class DerivedFactory : public ShapeFactory
{
public:
    DerivedFactory(ShapeType type)
    {
        ShapeFactory::GetShapeFactory().RegisterFactory(type, this);
    }
    ~DerivedFactory() {}
    Shape* Create() { return new ShapeClass(); }
};

ShapeFactory.cpp

#include "ShapeFactory.h"

//mapTypeShapeFactoryByType ShapeFactory::mapShapeTypeByFactory;
//ShapeFactory* ShapeFactory::mInstance = NULL;

ShapeFactory& ShapeFactory::GetShapeFactory()
{
    static ShapeFactory instance;
    return instance;
}

Shape * ShapeFactory::CreateShape(ShapeType type)
{
    if (mapShapeTypeByFactory.find(type) != mapShapeTypeByFactory.end())
        return mapShapeTypeByFactory[type]->Create();
    else
        return nullptr;
}

void ShapeFactory::RegisterFactory(ShapeType type, ShapeFactory * factory)
{
    mapShapeTypeByFactory[type] = factory;
}

Shape.h

#pragma once

#include <string>
using namespace std;

enum ShapeType
{
    Type_Unknown,
    Type_Circle,
    Type_Rectangle,
    Type_Polygon
};

class Shape
{
    std::string name;
public:
    virtual ~Shape() {}
    virtual ShapeType GetType() { return Type_Unknown; }
};

Rectangle.h

#pragma once
#include "Shape.h"
#include <iostream>

using namespace std;

class Rectangle : public Shape
{
public:
    Rectangle();
    virtual ~Rectangle();
    virtual ShapeType GetType() { return Type_Rectangle; }
private:
    float points[4][3];
};

Rectangle.cpp

#include "Rectangle.h"
#include "ShapeFactory.h"

static DerivedFactory<Rectangle> RectangleFactory(Type_Rectangle);

Rectangle::Rectangle()
{
    cout << "The factory created new Rectangle! \n";
}

Rectangle::~Rectangle()
{
    cout << "The Rectangle object was destroyed \n";
}

Circle.h

#pragma once
#include "Shape.h"
#include <iostream>

using namespace std;

class Circle : public Shape
{
public:
    Circle();
    virtual ~Circle();
    virtual ShapeType GetType() { return Type_Circle; }

private:
    float center[3];
    float radius;
};

Circle.cpp

#include "Circle.h"
#include "ShapeFactory.h"

static DerivedFactory<Circle> CircleFactory(Type_Circle);

Circle::Circle()
{
    cout << "The factory created new Circle! \n";
}

Circle::~Circle()
{
    cout << "The Circle object was destroyed \n";
}

main.cpp

#include <iostream>
#include <string>
#include <map>
#include "ShapeFactory.h"
#include "Shape.h"
#include "Circle.h"
#include "Rectangle.h"

using namespace std;

int main()
{
    ShapeFactory& factory = ShapeFactory::GetShapeFactory();

    Circle* vec = (Circle*)factory.CreateShape(Type_Circle);
    cout << "Object type is : " << vec->GetType() <<"\n";
    factory.DestroyShape(vec);

    Rectangle* con = (Rectangle*)factory.CreateShape(Type_Rectangle);
    cout << "Object type is : " << con->GetType() << "\n";
    factory.DestroyShape(con);



    getchar();
    return 0;
}

Thanks!!

Piyush Soni
  • 1,356
  • 3
  • 17
  • 40
  • Please provide a minimal but complete example, in the question itself, so that readers can try this. For now voting to close as **lacking relevant example**. – Cheers and hth. - Alf Sep 02 '16 at 03:30
  • @Cheersandhth.-Alf : I uploaded the project on github specifically to ask the question here, as it had multiple files, but now I will edit the question to add them all here. I however don't understand the eagerness to "close" a question so quick without waiting for even a couple of hours to let the author edit the question. It has happened multiple times that the requested edit is done, but then no one visits a closed question because it needs more votes than just mine to reopen. That can't be a way to help beginners. – Piyush Soni Sep 02 '16 at 05:44

1 Answers1

0

After compilation, the linker resolves all the symbols in your object files. Function declaration, static or otherwise, alone is not sufficient for the the compiler to generate symbols that will be eventually linked or resolved to its definition - unless there is a need for it like when it is invoked in compiled code.

This related question Static variables initialisation order also provides some more insight.

You might want to review your code to ensure there is a 'need' to resolve your derived classes.

As @alf recommends, including a minimal code snippet in your question will help focus any answers here.

Community
  • 1
  • 1
sith
  • 447
  • 7
  • 15
  • Thanks, I have edited the question now to include the code here itself. I am not sure the question is related, my static object is just not initialized, I'm not concerned about their order as long as it happens automatically. – Piyush Soni Sep 02 '16 at 06:40
  • Which line(s) of all that code are you expecting to trigger a call to the drived class constructor? BTW, that is a lot of code. If you can illustrate your problem with a few trivial classes less than 5 lines each, that will help focus my responses. – sith Sep 02 '16 at 07:36
  • I'm expecting the derived Factory class constructor calls to be made in Rectangle.cpp and Circle.cpp, at the top where I declare static objects. Yes, that's a lot of code, but I wanted to upload the exact sample I'm facing trouble with. I could remove one of the derived classes though from the list for the sample purpose. Thanks! – Piyush Soni Sep 02 '16 at 07:51
  • quick inspection shows nothing very-obviously wrong. May be you are facing a 'build system issue'. To track issues such as this 1) ensure that the files of your "missing object constructor" actually do get pulled in for compilation in your build setup. 2) if possible, move all your static instantiation adjacent to 'the-problem-location/file' - see if none of the derived instances get created. ( or move them all to the working-location/file ) - 3) cat all the derived classes .h and .cpp into one monolith and continue investigating along these lines... – sith Sep 02 '16 at 09:07
  • Yes, the file is getting pulled in compilation, I confirmed that. Also, I checked that if I move (for example) Rectangle.cpp's static derivedfactory object to Circle.cpp class, both gets created, if I move the other way round, none gets created. There's some problem with this one file, but I don't understand what. :( ... Can I find out something from the obj files they produce? – Piyush Soni Sep 02 '16 at 12:12
  • there you go. its likely a build issue - see if you introduce deliberate syntax errors around your rectangle static instantiation lines, whether or not the build catches it... – sith Sep 02 '16 at 16:14
  • Hi, I had tried that as well. It does cause compile time errors if I make any little deliberate mistake there, confirming that the changes are indeed getting compiled. There's probably something at link time and I don't know what. – Piyush Soni Sep 03 '16 at 04:21
  • I found out that the reason was that the static object is in a static library which is linked to my executable. Now, I don't know how do we force it. /OPT:NOREF linker option doesn't help, /WHOLEARCHIVE I think is not an option in MSVC11. – Piyush Soni Sep 05 '16 at 13:27
  • pure speculation from this point: none of the symbols in the static lib are referenced else where in the project. the linker throws out the whole lib during. so review the code and discover a chain of dependency that references this static object. – sith Sep 06 '16 at 02:55
  • Yes, they are not directly, the only purpose is to automatically register themselves to the factory, so that later a virtual method can be called on them. – Piyush Soni Sep 06 '16 at 03:43