2016-12-29 71 views
3

因此,我正在使用供應商應用程序中的一些新代碼,並且我發現他們的一個庫中使用了Singleton模式。在那裏他們使用Helper來實例化單例。爲什麼這是必要的?爲什麼這個單例實現使用私有類(C++)?

庫頭文件:

Class LibExample { 

public: 
    static LibExample* getInstance(); 

private: 
    class Helper { 
    public: 
     Helper() { 
      libExampleInstance = new LibExample(); 
     } 
     ~Helper() { 
      delete libExampleInstance; 
     } 

     LibExample* libExampleInstance; 
    }; 

    static LibExample* m_instance; 

    LibExample(); 
    virtual ~LibExample(); 
    LibExample (const LibExample&) {}; 
    LibExample& operator=(const LibExample&) { 
     return *(LibExample::getInstance()); 
    } 
}; 

在.cpp文件:

LibExample* LibExample::m_instance = NULL; 

LibExample* LibExample::getInstance() { 
    static Helper instance; 
    if(m_instance == NULL) { 
     m_instance = instance.libExampleInstance; 
     int ret = m_instance->init(); 
     if(ret < 0) { 
      m_instance = NULL; 
     } 
    } 
    return m_instance; 
} 
+2

我想:能夠在每次失敗的'init'完成時不需要釋放/重新分配內存就可以清空實例'm_instance'。我不明白的是,爲什麼如果它不涉及多態性,他們會在堆上分配內存,而不是在堆棧上。 –

+2

@ChrisR。''我不明白的是爲什麼他們會在堆上分配內存而不是在堆棧上'我不知道這個特殊情況,但是在某些情況下(即當您使用嵌入式時),堆棧大小可能會受到限制,因此足夠大的對象實例根本無法適用。 – SingerOfTheFall

回答

2

在那裏,他們用 '助手' 來實例化單。爲什麼這是必要的?

不是。這裏可以使用Helper來允許m_instance == NULL測試,並且在首次使用getInstance時調用init,但init也可以在LibExample構造函數中運行。可能有一個不起眼的原因,但恕我直言,這種設計只是過於複雜。

你可以有:

Class LibExample { 

public: 
    static LibExample* getInstance(); 

private: 
    LibExample(); 
    virtual ~LibExample(); 
    LibExample (const LibExample&) {}; 
    LibExample& operator=(const LibExample&) { 
     return *(LibExample::getInstance()); 
    } 
}; 

LibExample* LibExample::getInstance() { 
    static LibExample instance; 
    static LibExample* p_instance = NULL; 
    if(p_instance == NULL) { 
     int ret = instance.init(); 
     if(ret >= 0) { 
      p_instance = &instance; 
     } 
    } 
    return p_instance; 
} 

編輯:

正如在評論中指出的@SingerOfTheFall:

我認爲這樣做是爲了實現某種後期初始化:如果init()第一次失敗,則單態本身並不需要重新構造,並且下次調用實例時它將嘗試重新初始化自身。

仍然Helper沒有必要:我相應地修改了我的代碼。

+2

我認爲這樣做是爲了實現某種遲後初始化:如果init()第一次失敗,單例本身不需要重新構造,它會嘗試重新初始化下一個實例被調用。 – SingerOfTheFall

+0

@SingerOfTheFall你說得對,我在我的回答中集成了這個 – wasthishelpful

+0

我覺得新的代碼可能還是會有一些問題,就像多個線程會調用'init'一樣,因此一個鎖無法避免。 – Danh

相關問題