2012-05-13 53 views
4

我有一個類實現了singelton設計模式。 我知道有些人不認爲這是一個好主意,但它有很大幫助,使用單例時內存泄漏

反正 - 我有內存泄漏和vlagrind指出我這些行:

_singleton = new Manager(); //Manager::instance() (Manager.cpp:18) 

而且

Manager::Manager() : _file(new ofstream), _tasks(new map<int, Task *>()), 
     _idState(new map<int, int>()), _closing(false), _pending(false), 
     _lock(new pthread_mutex_t), _endLock(new pthread_mutex_t), _cond(new pthread_cond_t), 
     _flushCond(new map<int, pthread_cond_t *>()), _attr(new pthread_attr_t) { 
//The last line is line 25 in Manager::Manager 

現在在管理器的析構函數中我不能明確地刪除它,因爲它創建了一個愚蠢的循環(因爲在刪除_singleton時會調用析構函數導致無限循環)。我該如何擺脫這種泄漏?謝謝!

P.s.這裏是Valgrind的輸出:

==17823== 512 bytes in 1 blocks are definitely lost in loss record 2 of 2 
==17823== at 0x4C27297: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) 
==17823== by 0x40151E: Manager::Manager() (Manager.cpp:25) 
==17823== by 0x4014DB: Manager::instance() (Manager.cpp:18) 
==17823== by 0x406475: initdevice(char*) (outputdevice.cpp:66) 
==17823== by 0x4061D5: main (driver.cpp:21) 
==17823== 
==17823== LEAK SUMMARY: 
==17823== definitely lost: 512 bytes in 1 blocks 
= =17823== indirectly lost: 0 bytes in 0 blocks 
==17823==  possibly lost: 288 bytes in 1 blocks 
==17823== still reachable: 0 bytes in 0 blocks 
==17823==   suppressed: 0 bytes in 0 blocks 

增加:這裏就是我創建管理代碼:

Manager.h: 
class Manager { 
public: 
    ~Manager(); 
    static Manager * instance(); 
private: 
    Manager(); 
    static Manager * _singleton; 
}; 

和實現:

Manager.cpp: 
Manager * Manager::_singleton = 0; 

Manager * Manager::instance() { 
    if (!_singleton) 
     _singleton = new Manager(); 
    return _singleton; 
} 
+0

「現在在管理器的析構函數中,我不能明確地刪除它,因爲它創建了一個愚蠢的循環。」 - 那是什麼意思? –

+0

向我們展示瞭如何創建和銷燬管理器實例。 – Zuljin

+0

不要用指針來做,它會更好。 http://stackoverflow.com/a/1008289/14065它甚至成爲gcc線程安全(請參閱鏈接問題中的註釋)。即使你使用指針,你也不應該返回一個指針,你應該從'instance()'返回一個引用,否則調用者不確定他們是否應該刪除這個對象,而他們從來不應該這樣做。 –

回答

4

在C++中實現單例的一種常見方式是將實例設置爲實例getter中的static-static std::unique_ptr<T>,而不是類靜態變量。這確保了在程序完成時調用析構函數,並且可以創建一個多態訪問的實例,例如通過一個指向抽象基類的指針。

Scott Meyers在his "More Effective C++" book中就此主題進行了很好的討論。

+0

我不認爲這是問題,因爲我明確地調用析構函數 – yotamoo

+0

@yotamoo您沒有在多線程環境中使用它,是嗎?因爲如果兩個線程試圖同時獲取實例,其中一個會泄漏'Manager'。 – dasblinkenlight

+0

@dasblinkenlight雖然這是一個正確的問題,但如果他一直看到這一點,這將是非常奇怪的。 – KillianDS

2

Manager靜態對象,而且它的構造和析構函數會自動被調用。或者,如果您必須用operator new進行分配,請將其放入智能指針(如果可以,則爲unique_ptr,否則爲auto_ptr),以便在指針位於指針時將其銷燬。

+1

除了當你將變量設置爲靜態時,你可能需要擔心全局創建順序,除非你的單例用於任何全局變量的初始化。因此,它的一個好地方可能在Meyers單身人士的「實例()」函數中。這保證了順序,因爲第一個函數使用強制初始化。 –

+0

因此,「如果您必須使用operator new分配它」位 - 創建順序中的依賴關係與構造函數參數同構。 –