2013-06-20 99 views
1

我做了一個簡單的單例類。 運行測試時,我得到了一些weired結果。C++,單例類的析構函數再次被調用

析構函數被再次調用。

這是結果和我的代碼。

結果:我預計析構函數被調用4次,因爲我叫GetInstance() 4次。 但是 Desctuructor被稱爲5次

Start Test 
TestClass Constructor 
    TestClass Destructor 
    TestClass Destructor 
    TestClass Destructor 
    TestClass Destructor 
    TestClass Destructor 

singleton.h

#ifndef SINGLETON_H_ 
#define SINGLETON_H_ 

#include "basictype.h" 

namespace common { 
namespace internal { 

// Usage : 
// MyClass mine = common::internal::Singleton<MyClass>::GetInstace(); 
// mine.foo(); 

// This Singleton class is maybe the best one avoiding memory allocation. 
// See http://stackoverflow.com/questions/1008019/c-singleton-design-pattern/1008289#1008289 
template <typename Type> 
class Singleton { 
public: 
    static Type& GetInstance() { 
    static Type instance; 
    return instance; 
    } 
private: 
    Singleton() {}; 

    DISALLOW_COPY_AND_ASSIGN(Singleton); 
}; 

} // namespace internal 
} // namespace common 

#endif // SINGLETON_H_ 

的main.c

#include <iostream> 
#include "singleton.h" 

class TestClass { 
public: 
    TestClass() { 
    std::cout << "TestClass Constructor" << std::endl; 
    } 
    ~TestClass() { 
    std::cout << " TestClass Destructor" << std::endl; 
    } 
}; 

void runSingletonTest() { 
    TestClass tc = common::internal::Singleton<TestClass>::GetInstance(); 
    TestClass tc2 = common::internal::Singleton<TestClass>::GetInstance(); 
    TestClass tc3 = common::internal::Singleton<TestClass>::GetInstance(); 
    TestClass tc4 = common::internal::Singleton<TestClass>::GetInstance(); 
} 

int main(){ 
    std::cout << "Start Test" << std::endl; 
    runSingletonTest(); 
    return 0; 
} 
+2

這不是一個真正的單身人士,對不對?你的構造函數和析構函數應該是私有的;由GetInstance中的靜態聲明創建的實例應該是唯一的(如果您遵循正確的模式)。 –

回答

8

實際上,你有5個TestClass在實例代碼。

第一種是通過

static Type instance; 

使用默認的構造創建。這會在您的輸出中生成行TestClass Constructor

其他4通過

TestClass tc = common::internal::Singleton<TestClass>::GetInstance(); 
TestClass tc2 = common::internal::Singleton<TestClass>::GetInstance(); 
TestClass tc3 = common::internal::Singleton<TestClass>::GetInstance(); 
TestClass tc4 = common::internal::Singleton<TestClass>::GetInstance(); 

使用拷貝構造創建。複製構造函數由編譯器生成,不輸出任何內容(這就是爲什麼在輸出中只能看到一個TestClass Constructor)的原因。因此,有5個TestClass的實例被破壞。

注意:你的Singleton類是不是真的是一個單身人士。要正確遵循單件模式,你應該禁止複製,並通過聲明(複印件)構造函數和析構函數爲private分配:

template <typename Type> 
class Singleton { 
public: 
    static Type& GetInstance() { 
    static Type instance; 
    return instance; 
    } 
private: 
    Singleton() {} 
    ~Singleton() {} 

    // Dont forget to declare these two. You want to make sure they 
    // are unaccessable otherwise you may accidently get copies of 
    // your singleton appearing. 
    Singleton(const Singleton&);    // Don't Implement 
    Singleton& operator=(const Singleton&);  // Don't implement 
}; 

有一些關於C++ Singleton design pattern有益的討論。

如果C++ 11是可用的,最好是用

private: 
    Singleton() = default; 
    ~Singleton() = default; 

    Singleton(const Singleton&) = delete; 
    Singleton& operator=(const Singleton&) = delete; 

這確保了沒有人,甚至不是類本身,可以調用拷貝或複製分配功能。

+4

如果C++ 11可用,最好替換這些'; //不要用'= ​​delete;'實現''。這確保了沒有人,甚至不是類本身,都可以調用複製或複製分配功能。你可以使用'= default;'而不是空的大括號用於私有構造函數和析構函數。 – bames53

+0

@ bames53感謝您的建議。 – Yang

0

模板中的「靜態類型實例」正在創建另一個實例。

0

您錯誤地使用了邁爾的單身模式。

的getInstance應該有形式:

Singleton & GetInstance() { 
    static Singleton instance; 
    return instance; 
} 
+0

它會比這個修復更好一點。創建'TestClass'的副本沒有限制。 –

1

因此,有一個Singleton模板類是矯枉過正,而不是必要的。 Singleton是一種設計模式,而不是一種類型。

對於你想一個單身,只是每個類T:

  1. 添加instance靜態函數
  2. 使私有的默認構造函數(只有調用它instance法)
  3. 刪除複製構造函數

這將阻止創建多個類型爲T的實例。

嘗試以下操作:

class TestClass { 
public: 

    // 1 
    static TestClass& instance() { static TestClass x; return x; } 

private: 

    // 2 
    TestClass() { 
    std::cout << "TestClass Constructor" << std::endl; 
    } 

    // 3 
    TestClass(const TestClass&) = delete; 

    ~TestClass() { 
    std::cout << " TestClass Destructor" << std::endl; 
    } 
}; 

void runSingletonTest() { 
    TestClass& tc = TestClass::instance(); 
    TestClass& tc2 = TestClass::instance(); 
    TestClass& tc3 = TestClass::instance(); 
    TestClass& tc4 = TestClass::instance(); 
} 

現在你有4個引用同一個對象,你可以不小心創建第二個識別TestClass。

0

得到它的工作,你應該:

  1. 製作Singleton的構造函數,拷貝構造函數和受保護的賦值運算符(不是私人)。
  2. 從Singleton模板派生TestClass。

    class TestClass:public Singleton { ... };

嘗試,讓我知道它是否適合你;)