2014-08-29 3 views
1

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; 

}

+0

귀하의 컴파일러는 무엇입니까? 올바르게 기억한다면 부작용이있는 생성자를 최적화해서는 안됩니다 ... – Quentin

+0

이 기사에서 Registrar 클래스는 템플릿입니다. 코드 스 니펫에서는 그렇지 않습니다. 그러면 등록 할 클래스를 어떻게 알 수 있습니까? – Sebastian

+3

가능한 중복 : http://stackoverflow.com/q/1300836 문제는 정적 초기화 순서 실패입니다. – dyp

답변

1

, 나는 수동으로 공장 클래스의 람다 제작자를 등록하여 선택했다. 매크로가 만들어지고 사용되며 코드 줄 수가 정확히 동일하면 매우 간단합니다.