2014-11-17 5 views
1

공유 라이브러리에 링크 된 실행 파일에서 싱글 톤에 액세스 한 다음 공유 라이브러리 내에서 동일한 싱글 톤에 액세스하면 두 개의 인스턴스가 생성됩니다.Windows의 C++ 공유 라이브러리에있는 Singleton의 다중 인스턴스

허용되지 않습니까? 아니면 잘못된 것이 있습니까?

설명 할 몇 가지 코드가 있습니다. 나는 Singleton.h, Manager.h, Window.h, Window.cpp 및 DeclSpec.h

를 포함하는 공유 라이브러리를 생성

싱글 템플릿 클래스 :

#ifndef SINGLETON_H 
#define SINGLETON_H 

#include <memory> 
#include <iostream> 

template <typename T> 
class Singleton 
{ 
private: 
    static std::unique_ptr<T> s_instance; 

public: 
    static T &instance() 
    { 
     if (!s_instance) { 
      std::cout << "Creating..." << std::endl; 
      s_instance = std::make_unique<T>(); 
     } 

     return *s_instance; 
    } 
}; 

template <typename T> 
std::unique_ptr<T> Singleton<T>::s_instance; 

#endif //SINGLETON_H 

내가 싱글은 관리자 클래스를 생성 :

#ifndef MANAGER_H 
#define MANAGER_H 

#include "Singleton.h" 

class Manager : public Singleton<Manager> 
{ 
}; 

#endif //MANAGER_H 

그런 다음 관리자를 사용하는 동일한 라이브러리 내에 창 클래스가 있습니다. 여기

는 시간입니다 (DECLSPEC이 DeclSpec.h에 정의되어 있으며 라이브러리 내보내기/가져 오기 핸들) : 여기
#ifndef WINDOW_H 
#define WINDOW_H 

#include "DeclSpec.h" 

class DECLSPEC Window 
{ 

public: 
    Window(); 

}; 

#endif //WINDOW_H 

는 CPP입니다 : 마지막으로

#include "Manager.h" 
#include "Window.h" 

Window::Window() 
{ 
    Manager &m = Manager::instance(); 
} 

, 나는 실행 파일을 만드는 것이 위의 공유 라이브러리에 간단한 main.cpp로 링크되어 있습니다 :

#include "Manager.h" 
#include "Window.h" 

int main(void) 
{ 
    Manager &m = Manager::instance(); 
    Window w; 

    return 0; 
} 

출력 :

Creating... 
Creating... 

싱글 톤이 두 번 생성됩니다.

모든 포인터?

+0

사용 공장 한스 옆모습이 제안, 아니면 그냥 네임 스페이스로 내 보낸 함수를 사용

그래서 완전히 싱글의 템플릿 특수화를 인스턴스화 컴파일러를 강제로 Manager.cpp에 다음을 추가 나는 여기에 설명 : http://stackoverflow.com/a/26954789/805509 그들을 내보낼 수 있습니다.이것이 당신을위한 옵션이라면, 코멘트를 남겨주세요. 나는 완전한 대답을했습니다. 그러나'Manager'와 같은 것을 클래스로 사용하거나 어딘가에 인스턴스에 대한 포인터를 가지고 있어야하는 것은 아닙니다. – PuerNoctis

답변

0

다른 클래스와 마찬가지로 컴파일러에서 템플릿 클래스 특수화를 내보내거나 가져와야합니다. 템플릿 전문화를 가져 오기 또는 내보내기로 올바르게 선언하는 방법은 다음과 같습니다.

#ifndef MANAGER_H 
#define MANAGER_H 

#include "Singleton.h" 

// <BEGIN modifications> 
// forward declare the Manager class 
class Manager; 
// delcare your specialization as import or export 
// NOTE: this only works on win32. 
// For other platforms you would use the 'extern' keyword, and it does not go in the same place as DECLSPEC 
template class DECLSPEC Singleton<Manager>; 
// <END modifications> 

class Manager : public Singleton<Manager> 
{ 
}; 

#endif //MANAGER_H 

여기서 목표는 DECLSPEC을 사용하여 Singleton의 특정 전문에 태그를 지정하는 것입니다. 기본 실행 파일에 존재하지 않는 다른 유형의 싱글 톤을 원할 수 있기 때문에 템플릿 클래스 자체에 태그를 지정하지 않아도됩니다.

Microsoft 컴파일러는 declspec 태그가 지정된 템플릿을 구현하지 않습니다. 다른 컴파일러 (clang, gcc)는이 목적으로 'extern'키워드를 사용합니다. 따라서 cpp 파일 중 하나에서 명시 적으로 템플릿을 인스턴스화해야 할 책임이 있습니다. 이 작업을 잊어 버리면 클래스 멤버 함수를 만든 것처럼 구현 링하는 것처럼 링커 오류가 발생합니다.

반대로, DECLSPEC없이 코드에서 어딘가에서 싱글 톤을 참조하는 것을 잊으면 (예 : 클래스를 선언 할 때와 같이) '여러 기호로 정의 된'링커 오류가 발생합니다.

template class Singleton<Manager>;