I am trying to create "plugin" factory. When an user requests creation of an object factory queries it's child factories and picks suitable one to create the object.

Instances of child libraries are static objects. When they are created they register themselves to the top level factory.

Here is simplified version:

// ifactory.h
#ifndef _IFACTORY_H_
#define _IFACTORY_H_

#include <string>

class IFactory {
public:
    virtual int createNumber(const std::string& name, std::pair<int, int> range) = 0;

    virtual std::string getName() const = 0;

    virtual ~IFactory() = default;
};

#endif
// defaul_factory.h:
#ifndef _DEFAULT_FACTORY_H_
#define _DEFAULT_FACTORY_H_

#include "ifactory.h"

#include <vector>
#include <stdexcept>

class DefaultFactory : public IFactory {
public:
    int createNumber(const std::string& name, std::pair<int, int> range) override {
        for (auto factory: g_factories) {
            if (factory->getName() == name) {
                return factory->createNumber(name, range);
            }
        }

        throw std::runtime_error{"No factory can create requested number"};
    }

    std::string getName() const override {
        return "default";
    }

    static void registerFactory(IFactory* factory) {
        g_factories.push_back(factory);
    }

private:
    static std::vector<IFactory*> g_factories;
};
#endif
// defalut_factory.cpp
#include "default_factory.h"

std::vector<IFactory*> DefaultFactory::g_factories;
// even_factory.cpp
#include "default_factory.h"

class EvenFactory : public IFactory {
public:
    EvenFactory() {
        DefaultFactory::registerFactory(this);
    }

    int createNumber(const std::string& name, std::pair<int, int> range) override {
        return range.first % 2 == 0 ? range.first + 4 : range.first + 3;
    }

    std::string getName() const override {
        return "even";
    }
};

// Hopefully registers itself to the default factory
static EvenFactory evenFactory;
// main.cpp
#include "default_factory.h"

#include <iostream>

int main() {
    DefaultFactory factory;
    std::cout << factory.createNumber("even", {100, 200}) << std::endl;
}
# Makefile:
all: foo

foo: libdefault_factory.so libeven_factory.so main.cpp
    $(CXX) -L./ -o foo main.cpp -ldefault_factory -Wl,--no-as-needed -leven_factory

libdefault_factory.so: default_factory.cpp default_factory.h ifactory.h
    $(CXX) -shared -fPIC -o libdefault_factory.so default_factory.cpp

libeven_factory.so: even_factory.cpp default_factory.h ifactory.h
    $(CXX) -shared -fPIC -o libeven_factory.so even_factory.cpp

bar: default_factory.cpp even_factory.cpp default_factory.h ifactory.h main.cpp
    $(CXX) -o bar main.cpp default_factory.cpp even_factory.cpp

.PHONY: clean

clean:
    rm foo bar *.so

When I execute foo I get a runtime exception which is thrown from DefalutFactory, as if the constructor was not run for evenFactory.

Running bar prints 104, as expected.

Why the constructor is not invoked for the foo?

NOTE: I tested the example with g++ version 9 and g++ version 10.2.

0

There are 0 best solutions below