2013-12-17 45 views
3

我有以下結構:遞延成員建設

struct Logger::LoggerImpl { 
    std::wofstream loggerStream; 
} 

當我創建一個LoggerImpl,顯然是一個std :: wofstream將被隱式創建(通過編譯器的默認構造函數)。

我的問題是,有沒有辦法阻止(或推遲)wofstream的構造,而不使用指針?因爲我稍後會用給定的文件名創建它。

我知道,在這種情況下,它沒有什麼區別,但我在理論基礎上提出要求。

+0

「不使用指針」 - 任何理由呢?指針似乎是一個明顯的解決方案。在初始化時顯然會分配它,如果你有任何參考,在任何階段顯然不能爲空。 –

+0

如果它不是一個指針,它將在構建父代的同時被構造;對此你可以做的不多。唯一的另一種選擇叫做兩部分構造,但是這將是'wofstream'類,而不是你的'Logger'類。 –

+0

你爲什麼不想用指針來做這個?有理由嗎? – Netherwire

回答

4

你可以,如果你伸展的定義,「不使用指針」是指「而無需直接使用std::wofstream *」:

struct Logger::LoggerImpl { 
    std::shared_ptr<std::wofstream> loggerStream; 


    void init() { 
     loggerStream = std::make_shared<std::wofstream>(); 
    } 
}; 

我說的拉伸,因爲你不處理直接std::wofstream *。這是我能想到的最好的。

+3

這是一個指針。 –

+0

_ [好的,你已經承認了。儘管如此,我還是覺得需要簡單地評論一下。 :P總而言之,你沒有回答這個問題,但我懷疑這是OP的正確方法,因爲至少他還有RAII在他身邊。 +1] _ –

+0

好吧,如果你仔細想想,你幾乎不能使用STL而不使用指針,因爲它們都是在內部使用指針來實現的。即使你在棧上聲明瞭一個'std :: wofstream',你仍然在使用指針,對吧?我想這裏同樣的事情。 std :: shared_ptr直接使用指針,並間接使用它。 – Anthony

1

推遲會員在各種情況下的建設很有意義。這裏有幾個方法可以做到這一點;實現之間的差異是由於不同的延期目的。

首次使用初始化;理由:直到需要時才浪費資源。

class Logger::LoggerImpl 
{ 
private: 
    std::wofstream * loggerStream; // Don't expose to other classes 

    std::wofstream * GetLoggerStreamImpl() 
    { 
     if(loggerStream == NULL) 
     { 
      loggerStream = new std::wofstream; 
     } 

     return loggerStream; 
    } 

public: 
    LoggerImpl() : loggerStream(NULL) 
    { 
    } 

    std::wofstream * GetLoggerStream() 
    { 
     return GetLoggerStreamImpl(); 
    } 

    void DoSomethingWithLoggerStream() 
    { 
     GetLoggerStreamImpl(); 
     // Do whatever you need with loggerStream 
    } 
}; 

通過專用方法初始化;原因:之前不知道初始化參數。

class Logger::LoggerImpl 
{ 
private: 
    std::wofstream * loggerStream; // Don't expose to other classes 

    std::wofstream * OpenLoggerStreamImpl(string filename) 
    { 
     if(loggerStream == NULL) 
     { 
      loggerStream = new std::wofstream(filename); 
     } 
     return loggerStream; 
    } 

public: 
    LoggerImpl() : loggerStream(NULL) 
    { 
    } 

    std::wofstream * OpenLoggerStream(string filename) 
    { 
     return OpenLoggerStreamImpl(filename); 
    } 

    void DoSomethingWithLoggerStream() 
    { 
     if(loggerStream == NULL) 
     { 
      throw Exception("Aye, Caramba! Logging stream wasn't open yet!"); 
     } 

     // Do whatever you need with loggerStream 
    } 
}; 
+0

考慮到OP提到他們的初學C++狀態,讓我指出你必須刪除'loggerStream',可能在LoggerImpl的析構函數中。另外,請參閱我的答案,瞭解如何在指針超出範圍時自動清理指針。 – Anthony

4

爲什麼不創建std::wofstream使用默認的構造函數,後來只是open()文件?綁定被包含對象的生命週期似乎是正確的方法。

在C++ 11中,您還可以將帶構造函數的對象放入union。當然,結果是你需要接管union成員的生命週期管理。然而,這種方式可以延遲某個特定成員的構建,直到以後。注意在下面的代碼中使用new實際上只是放置新的,構建一個對象到合適的位置。這裏是一個例子:

#include <iostream> 
#include <fstream> 
#include <new> 

class foo 
{ 
    bool constructed; 
    union helper { 
     helper() {} 
     ~helper() {} 
     std::ifstream stream; 
    } member; 
public: 
    foo(): constructed() {} 
    ~foo() { 
     if (constructed) { 
      using std::ifstream; 
      this->member.stream.~ifstream(); 
     } 
    } 
    void open(std::string const& name) { 
     new (&this->member.stream) std::ifstream(name); 
     constructed = true; 
    } 
    std::streambuf* rdbuf() { 
     return this->member.stream.rdbuf(); 
    } 
}; 

int main() 
{ 
    foo f; 
    f.open("foo.cpp"); 
    std::cout << f.rdbuf(); 
} 
+0

這是實際回答如何推遲成員構造而不使用指針(以及由堆分配的內存)的唯一文章。 –