2012-01-13 61 views
4

我通過使用boost :: scoped_ptr的實現了一個簡單單清除:爲什麼提高:: scoped_ptr的是在一個單獨的實施

template <class T> class Singleton : public boost::noncopyable { 
    public: 
     static T& instance() { 
      boost::call_once(init, flag); 
      return *t; 
     } 
     static void init() { 
      t.reset(new T()); 
     } 
    private: 
     static boost::scoped_ptr <T> t; 
     static boost::once_flag flag; 
}; 
template <class T> boost::scoped_ptr<T> Singleton<T>::t(0); 
template <class T> boost::once_flag Singleton<T>::flag = BOOST_ONCE_INIT; 

定義一個真正的單例類:

class S : public Singleton<S> { 
    public: 
     void p() { printf("hello");} 
}; 

然後我定義了在文件S.cpp靜態變量:

static volatile S &S_instance = S::instance(); 

在main.cpp中:

int main() 
{ 
     S &ss = S::instance(); 
     ss.p(); 
} 

運行這個程序,異常發生:

/usr/include/boost/smart_ptr/scoped_ptr.hpp:91:T &的boost :: scoped_ptr的::運算符*()const的[與T = S]:斷言`PX = 0' 失敗

跟蹤代碼,我發現一旦代碼離開靜態初始化段和靜態s_instance.t被清除後指的是S中的所有代碼: :實例將得到NULL scoped_ptr。有人知道原因嗎?

[更新] 我試圖把所有靜態到一個CPP文件(S1.cpp):

template <class T> boost::scoped_ptr<T> Singleton<T>::t(0); 
template <class T> boost::once_flag Singleton<T>::flag = BOOST_ONCE_INIT; 

static S& s_ins = S::instance(); 

並調試它與GDB,它看起來跟着我寫的順序。任何想法?

回答

2

一個可能的原因是,靜態template <class T> boost::scoped_ptr<T> Singleton<T>::t(0);被的static volatile S &S_instance = S::instance();後初始化,因此與0預先存儲在t的值所替代。靜態變量的構建順序只在一個編譯單元中定義,我想你的情況t可以在main.cpp(或編譯時在兩個文件中實例化,並且鏈接器只需要選擇一個)而S駐留在S.cpp。只是一個猜測。

+0

首先感謝。但我試圖把所有的靜態文件放在cpp文件中: – 2012-01-13 19:06:46

+0

應該是這個原因。謝謝! – 2012-01-13 19:34:53

0

你的程序正常工作(當爲單個文件編譯)如果您刪除此行:

static volatile S &S_instance = S::instance(); 

確定。在我的機器上創建,不需要你S_instance聲明:

0000000000400d86 <__static_initialization_and_destruction_0(int, int)>: 
    400d86:  55      push %rbp 
    400d87:  48 89 e5    mov %rsp,%rbp 
    400d8a:  48 83 ec 10    sub $0x10,%rsp 
    400d8e:  89 7d fc    mov %edi,-0x4(%rbp) 
    400d91:  89 75 f8    mov %esi,-0x8(%rbp) 
    400d94:  83 7d fc 01    cmpl $0x1,-0x4(%rbp) 
    400d98:  75 43     jne 400ddd <__static_initialization_and_destruction_0(int, int)+0x57> 
    400d9a:  81 7d f8 ff ff 00 00 cmpl $0xffff,-0x8(%rbp) 
    400da1:  75 3a     jne 400ddd <__static_initialization_and_destruction_0(int, int)+0x57> 
    400da3:  b8 b8 40 40 00   mov $0x4040b8,%eax 
    400da8:  0f b6 00    movzbl (%rax),%eax 
    400dab:  84 c0     test %al,%al 
    400dad:  75 2e     jne 400ddd <__static_initialization_and_destruction_0(int, int)+0x57> 
    400daf:  b8 b8 40 40 00   mov $0x4040b8,%eax 
    400db4:  c6 00 01    movb $0x1,(%rax) 
    400db7:  be 00 00 00 00   mov $0x0,%esi 
    400dbc:  bf b0 40 40 00   mov $0x4040b0,%edi 
    400dc1:  e8 3c 05 00 00   callq 401302 <boost::scoped_ptr<S>::scoped_ptr(S*)> 
    400dc6:  b8 da 13 40 00   mov $0x4013da,%eax 
    400dcb:  ba 90 40 40 00   mov $0x404090,%edx 
    400dd0:  be b0 40 40 00   mov $0x4040b0,%esi 
    400dd5:  48 89 c7    mov %rax,%rdi 
    400dd8:  e8 8b fd ff ff   callq 400b68 <[email protected]> 
    400ddd:  c9      leaveq 
    400dde:  c3      retq 

當您S_instance聲明編譯:

0000000000400d86 <__static_initialization_and_destruction_0(int, int)>: 
    400d86:  55      push %rbp 
    400d87:  48 89 e5    mov %rsp,%rbp 
    400d8a:  48 83 ec 10    sub $0x10,%rsp 
    400d8e:  89 7d fc    mov %edi,-0x4(%rbp) 
    400d91:  89 75 f8    mov %esi,-0x8(%rbp) 
    400d94:  83 7d fc 01    cmpl $0x1,-0x4(%rbp) 
    400d98:  75 4f     jne 400de9 <__static_initialization_and_destruction_0(int, int)+0x63> 
    400d9a:  81 7d f8 ff ff 00 00 cmpl $0xffff,-0x8(%rbp) 
    400da1:  75 46     jne 400de9 <__static_initialization_and_destruction_0(int, int)+0x63> 
    400da3:  e8 c2 04 00 00   callq 40126a <Singleton<S>::instance()> 
    400da8:  48 89 05 01 33 00 00 mov %rax,0x3301(%rip)  # 4040b0 <S_instance> 
    400daf:  b8 c0 40 40 00   mov $0x4040c0,%eax 
    400db4:  0f b6 00    movzbl (%rax),%eax 
    400db7:  84 c0     test %al,%al 
    400db9:  75 2e     jne 400de9 <__static_initialization_and_destruction_0(int, int)+0x63> 
    400dbb:  b8 c0 40 40 00   mov $0x4040c0,%eax 
    400dc0:  c6 00 01    movb $0x1,(%rax) 
    400dc3:  be 00 00 00 00   mov $0x0,%esi 
    400dc8:  bf b8 40 40 00   mov $0x4040b8,%edi 
    400dcd:  e8 3c 05 00 00   callq 40130e <boost::scoped_ptr<S>::scoped_ptr(S*)> 
    400dd2:  b8 e6 13 40 00   mov $0x4013e6,%eax 
    400dd7:  ba 90 40 40 00   mov $0x404090,%edx 
    400ddc:  be b8 40 40 00   mov $0x4040b8,%esi 
    400de1:  48 89 c7    mov %rax,%rdi 
    400de4:  e8 7f fd ff ff   callq 400b68 <[email protected]> 
    400de9:  c9      leaveq 
    400dea:  c3      retq 

在後面的代碼中,你可以清楚地看到,對於靜態scoped_ptr的構造S_instance後會發生。

#include <cstdio> 

#include <boost/scoped_ptr.hpp> 
#include <boost/thread/once.hpp> 
#include <boost/noncopyable.hpp> 

template <class T> class Singleton : public boost::noncopyable { 
public: 
    static T& instance() { 
     boost::call_once(init, flag); 
     return *t; 
    } 
    static void init() { 
     t.reset(new T()); 
    } 
private: 
    static boost::scoped_ptr <T> t; 
    static boost::once_flag flag; 
}; 

template <class T> boost::scoped_ptr<T> Singleton<T>::t(0); 
template <class T> boost::once_flag Singleton<T>::flag = BOOST_ONCE_INIT; 

class S : public Singleton<S> { 
public: 
    void p() { printf("hello");} 
}; 

// static volatile S &S_instance = S::instance(); 

int main() 
{ 
    S &ss = S::instance(); 
    ss.p(); 
} 
0

我敢肯定,這是不確定的行爲,由於全局變量的不確定創建順序:

上面的方法從編譯。所以,你的S_instance首先初始化,然後template <class T> boost::scoped_ptr<T> Singleton<T>::t(0)

這樣一個簡單的程序就可以說明,什麼都有可能發生時,順序是相反的:

#include <iostream> 

std::string &getS(); 
std::string& t = getS(); 
std::string s("hello"); 
std::string &getS() {s = "world"; return s;} 

int main() 
{ 
    std::cout << t; 
} 

那麼,它崩潰了我g++和印刷品hellocl

0

我認爲這是錯誤的:

static volatile S &S_instance = S::instance(); 

貝科使用它創建並刪除實例。你想要一個指針,而不是一個參考。

static S *S_instance = &S::instance(); 

據我所知,引用超出範圍在.cpp文件的末尾。這個實例無論如何都不會被刪除,所以T可以只是一個空指針。

相關問題