2016-09-09 3 views
5

우리는 싱글 톤을 구현하기 위해 curiously recurring template pattern을 사용하고 있습니다. 그러나 최근의 Clang 버전에서는 Woundefined-var-template 경고가 나타납니다. "명시 적 인스턴스화 선언"을 추가하는 것이 좋습니다.Clang을 사용하여 CRTP Singleton을 컴파일 할 때 "명시 적 인스턴스화 선언"이 부족하다는 문제를 해결하는 방법은 무엇입니까?

이 작업을 시도했지만, 싱글 톤 템플릿 클래스 멤버 변수의 정의가있는 컴파일 단위에서 "인스턴스화 후 명시 적 전문화"에 대한 오류가 발생합니다.

이 경고로 강조 표시된 문제를 해결하는 적절한 구성 요소는 무엇입니까?


간체 정보 (논리의 대부분은 MCVE를 만들기 위해, 제거 된) :

SingletonBase.hh :

template < class T > class SingletonBase { 
public: 
    static T * get_instance() { 
    if (! instance_) { 
     instance_ = T::create_singleton_instance(); 
    } 
    return instance_; 
    } 
private: 
    static T * instance_; 
}; 

Singleton.hh :

#include "SingletonBase.hh" 

class Singleton : public SingletonBase<Singleton> { 
    friend class SingletonBase<Singleton>; 
public: 
    int do_stuff(int v) { return v+2; } 
private: 
    static Singleton * create_singleton_instance() { 
    return new Singleton; 
    } 
}; 

싱글 톤 .cc :

#include "Singleton.hh" 
template <> Singleton * SingletonBase<Singleton>::instance_(nullptr); 

최근 버전의 clang (3.9.0; but not clang 3.7), Singleton.cc 이외의 파일을 컴파일 할 때 경고 메시지가 나타납니다. 그것이 내가 명시 적 인스턴스화 선언 구문이되어야합니다 lead to believe이야 무엇으로 (-std = C++ 11 -Werror와)

In file included from OtherFile.cc:2: 
In file included from ./Singleton.hh:2: 
./SingletonBase.hh:5:16: warning: instantiation of variable 'SingletonBase<Singleton>::instance_' required here, but no definition is available [-Wundefined-var-template] 
     if (! instance_) { 
      ^
OtherFile.cc:5:25: note: in instantiation of member function 'SingletonBase<Singleton>::get_instance' requested here 
     return Singleton::get_instance()->do_stuff(4); 
         ^
./SingletonBase.hh:11:18: note: forward declaration of template entity is here 
     static T * instance_; 
      ^

./SingletonBase.hh:5:16: note: add an explicit instantiation declaration to suppress this warning if 'SingletonBase<Singleton>::instance_' is explicitly instantiated in another translation unit 
     if (! instance_) { 
      ^
1 error generated. 

나는, Singleton.hh의 마지막에 다음 줄을 추가했다. 그 OtherFile.cc를 컴파일하여 문제를 해결하는 동안 Singleton.cc

를 컴파일 할 때

extern template Singleton* SingletonBase< class Singleton >::instance_; 

, 그것은 새로운 오류가 발생

Singleton.cc:3:57: error: explicit specialization of 'instance_' after instantiation 
    template <> Singleton * SingletonBase<Singleton>::instance_(nullptr); 
                ^
./Singleton.hh:14:66: note: explicit instantiation first required here 
    extern template Singleton* SingletonBase< class Singleton >::instance_; 
                  ^
1 error generated. 
나는 이러한 경고/오류를 해결하기 위해 여기에 일을해야 무엇

? 내가 이해하지 못하는 명시 적 인스턴스화 선언에 대한 더 적절한 구문이 있습니까?

template<class T> 
struct SingletonBase { 
    static T& get_instance() { 
     static T instance; 
     return instance; 
    } 
}; 

이의 스레드로부터 안전하고 경고를 제거합니다

+2

왜 오 ​​왜? 고정 멤버 var를 만들고 잠금이 아니므로 스레드로부터 안전하지 않습니다. 당신은'get_instance()'에 그 static을 넣을 수 있습니다. if를 thread-safe로 남겨 둡니다. 기본 클래스는 이것이 싱글 톤인 것을 보장하지는 않지만 create_instance 함수가 필요합니다. 어느 시점에서든 인터페이스를 건드리지 않고 두 개의 'Singleton'인스턴스를 만들 수 있습니다. 그것을 파괴 할 수는 없습니다. 같은 시간에 기본 및 자손 (singleton)을 가질 수 있습니다. 당신은 유출하고 절대 소멸자를 부르지 않습니다. 고쳐? 이러한 소스를 삭제하고 다시 시작하십시오. (불쾌감을주지 않으면 적절한 지침을 제공 할 수 있습니다.) – lorro

+0

@ Iorro MCVE를 제공하기 위해 대부분의 세부 사항 (스레드 안전 비트 포함)을 찢어 냈습니다. "베스트 프랙티스"를 고려한 싱글 톤 구현을 가지고 있다면, 그것을 코멘트에 링크 할 수는 있지만 원래의 질문은 여전히 ​​유효합니다. –

+0

이것은 매우 중요합니다. 주 질문 섹션에 주석을 추가하는 것이 좋습니다. 그렇지 않으면 사람들이 컴파일러 오류가 아니라이를 수정하려고합니다. 멤버 변수 -> 함수 static 변수 수정이 작동합니까? 아니면 멤버로 유지해야 할 이유가 있습니까? – lorro

답변

1

내가 대신 싱글 톤의 구현을 추천 할 것입니다.

당신이 원하는 경우, 당신은 계속 할 수 create_singleton_instance :

template<class T> 
struct SingletonBase { 
    static T& get_instance() { 
     static T instance{T::create_singleton_instance()}; 
     return instance; 
    } 
}; 

하고 기능 구현을 변경 :

static SomeClass create_singleton_instance() { 
    return {}; 
} 
+0

.. _single_ton이 아닌 것을 제외하고. 이 시점에서 단일 인스턴스를 보증하지 않았습니다. – lorro

+0

그러면 생성자를 private로 만들고 부모를 친구로 만듭니다. –

+0

제안 된 솔루션은 Microsoft Windows 8 및 Visual Studio 2015 이하 버전에서 무언가를 깨뜨립니다. Microsoft는 [마법의 정적] (https://msdn.microsoft.com/en-us/library/hh567368.aspx) 일명 N2660 [동시성을 사용한 동적 초기화 및 파괴] (http : //www.open- std.org/jtc1/sc22/wg21/docs/papers/2008/n2660.htm). 컴파일러를 변경해도 수정되지 않습니다. 문제는 런타임과 플랫폼에 있습니다. 거의 10 년이 걸리는 핵심 언어 기능입니다. Microsoft는 결함을 무기로 사용하여 사람들이 Windows 10으로 업그레이드하도록했습니다. – jww

3

간단한 수정 SingletonBase.hh에 instance_을 정의하는 것입니다 :

template < class T > class SingletonBase { 
public: 
    static T * get_instance() { 
    if (! instance_) { 
     instance_ = T::create_singleton_instance(); 
    } 
    return instance_; 
    } 
private: 
    static T * instance_; 
}; 

template <typename T> 
T* SingletonBase<T>::instance_ = nullptr; 

그러나 요점은 보이지 않습니다. SingletonBase 인스턴스를 만들려면 T::create_singleton_instance()을 사용하십시오. 파생 클래스에 get_instance()을 구현할 수도 있습니다.

CRTP를 사용하여 단일 패턴을 구현하면 기본 클래스가 기본 생성자를 사용하여 파생 클래스의 인스턴스를 생성 할 수있는 경우에만 의미가 있습니다.

template < class T > class SingletonBase { 
    public: 
     static T& get_instance() { 
     static T instance_; 
     return instance_; 
     } 
    private: 
}; 

추가 읽기 : How to implement multithread safe singleton in C++11 without using <mutex>