here에 사용할 수있는 다음 문서를 기반으로 팩토리 클래스를 구현했습니다.팩토리 클래스 구현 문제
그러나 한 가지 문제가 있습니다. 컴파일러 최적화와 관련이 있다고 생각합니다.
Node (Node.h/Node.cpp) 클래스가 기본 클래스이고 예를 들어 BuildingLot.h (BuildingLot.h/BuildingLot.cpp) 클래스가 하위 클래스 인 클래스 계층 구조가 있습니다.
정적 파일로 선언 된 두 소스 파일에는 모두 Registrar 클래스가 있습니다.
Node.cpp :
static Registrar<Node> _registrar(“Node”);
BuildingLot.cpp는 :
static Registrar<BuildingLot> _registrar(“BuildingLot”);
나는 공장을 사용하려고하면, 그것은 노드 클래스에 대해 완벽하게 작동합니다. 그러나 FactoryLot의 인스턴스를 먼저 공장에 등록해야합니다. 단위 테스트에서
나는이 :NodePtr node = Factory::Instance()->Create(“Node”);
NodePtr bl = Factory::Instance()->Create(“BuildingLot”);
BL은 항상 nullptr입니다. 등록자 생성자는 실행되지 않으므로 Factory 클래스는 BuildingLot 클래스를 전혀 알지 못합니다. 내가 이렇게하면 :
BuildingLot b;
NodePtr node = Factory::Instance()->Create(“Node”);
NodePtr bl = Factory::Instance()->Create(“BuildingLot”);
다음 모든 작동합니다. 등록 기관이 호출되고 공장에서 BuildingLot을 만듭니다.
첫 번째 예에서는 BuildingLot이 사용되지 않았기 때문에 컴파일러가 최적화되어 있고 BuildingLot.cpp도 컴파일하지 않았다고 생각합니다.
이것이 가능합니까? 이 문제를 어떻게 해결할 수 있습니까?
편집 : 실제로 Registrar 클래스는 템플릿 클래스입니다. 방금 템플릿 매개 변수를 삽입하는 것을 잊었습니다.
여기 내 코드는 간단하게 만들 수 있습니다. 나는 아무것도 남기지 않았 으면 좋겠다. main()에서 첫 번째 줄의 주석 처리를 제거하면 모두 작동합니다.
NodeFactory.h :
class NodeFactory{
private:
/// Map of factory functions
std::map<std::string, std::function<std::shared_ptr<Node>(void)>> mFactoryFunctions;
public:
/// Get Singleton
static NodeFactory* Instance();
/// Register Function.
void Register(const std::string &name, std::function<std::shared_ptr<Node>(void)> factoryFunction);
/// Factory Function.
std::shared_ptr<Node> Create(const std::string &name);
};
NodeFactory.cpp :
/**
* Get Singleton
*/
NodeFactory* NodeFactory::Instance(){
static NodeFactory factory;
return &factory;
}
void NodeFactory::Register(const std::string &name, std::function<std::shared_ptr<Node>(void)> factoryFunction){
mFactoryFunctions[name] = factoryFunction;
}
std::shared_ptr<Node> NodeFactory::Create(const std::string &name){
if(mFactoryFunctions.find(name) == mFactoryFunctions.end())
return nullptr;
std::shared_ptr<Node> n = mFactoryFunctions[name]();
return n;
}
Registrar.h :
#define REGISTER_NODE_TYPE(NODE_TYPE) static NodeRegistrar<NODE_TYPE> _registrar(#NODE_TYPE);
template<class T>
class NodeRegistrar{
private:
public:
NodeRegistrar(const std::string &name){
NodeFactory::Instance()->Register(name,
[](void) -> std::shared_ptr<T> { return std::make_shared<T>(); }
);
}
};
Node.h :
class Node{
private:
/// The node ID.
NodeID mID;
public:
/* ****************************
* Construction & Destruction *
* ***************************/
Node();
Node(const NodeID &nodeID);
virtual ~Node();
};
Node.cpp :
REGISTER_NODE_TYPE(Node);
Node::Node(){
mID = -1;
}
Node::Node(const NodeID &nodeID){
mID = nodeID;
}
Node::~Node(){
}
BuildingLot.h :
class BuildingLot : public Node{
public:
BuildingLot();
BuildingLot(const NodeID &nodeID);
virtual ~BuildingLot();
};
BuildingLot.CPP :
REGISTER_NODE_TYPE(BuildingLot);
BuildingLot::BuildingLot(){
}
BuildingLot::BuildingLot(const NodeID &nodeID):Node(nodeID){
}
BuildingLot::~BuildingLot(){
}
MAIN.CPP : 결국
int main(int argc, const char * argv[]){
// BuildingLot bl; // if I uncomment this, then it works
std::shared_ptr<Node> node = NodeFactory::Instance()->Create("Node");
std::shared_ptr<Node> buildingLot = NodeFactory::Instance()->Create("BuildingLot");
if(node == nullptr)
std::cout << "node is nullptr" << std::endl;
if(buildingLot == nullptr)
std::cout << "buildingLot is nullptr" << std::endl;
return 0;
}
귀하의 컴파일러는 무엇입니까? 올바르게 기억한다면 부작용이있는 생성자를 최적화해서는 안됩니다 ... – Quentin
이 기사에서 Registrar 클래스는 템플릿입니다. 코드 스 니펫에서는 그렇지 않습니다. 그러면 등록 할 클래스를 어떻게 알 수 있습니까? – Sebastian
가능한 중복 : http://stackoverflow.com/q/1300836 문제는 정적 초기화 순서 실패입니다. – dyp