我有以下結構:遞延成員建設
struct Logger::LoggerImpl {
std::wofstream loggerStream;
}
當我創建一個LoggerImpl,顯然是一個std :: wofstream將被隱式創建(通過編譯器的默認構造函數)。
我的問題是,有沒有辦法阻止(或推遲)wofstream的構造,而不使用指針?因爲我稍後會用給定的文件名創建它。
我知道,在這種情況下,它沒有什麼區別,但我在理論基礎上提出要求。
我有以下結構:遞延成員建設
struct Logger::LoggerImpl {
std::wofstream loggerStream;
}
當我創建一個LoggerImpl,顯然是一個std :: wofstream將被隱式創建(通過編譯器的默認構造函數)。
我的問題是,有沒有辦法阻止(或推遲)wofstream的構造,而不使用指針?因爲我稍後會用給定的文件名創建它。
我知道,在這種情況下,它沒有什麼區別,但我在理論基礎上提出要求。
你可以,如果你伸展的定義,「不使用指針」是指「而無需直接使用std::wofstream *
」:
struct Logger::LoggerImpl {
std::shared_ptr<std::wofstream> loggerStream;
void init() {
loggerStream = std::make_shared<std::wofstream>();
}
};
我說的拉伸,因爲你不處理直接std::wofstream *
。這是我能想到的最好的。
這是一個指針。 –
_ [好的,你已經承認了。儘管如此,我還是覺得需要簡單地評論一下。 :P總而言之,你沒有回答這個問題,但我懷疑這是OP的正確方法,因爲至少他還有RAII在他身邊。 +1] _ –
好吧,如果你仔細想想,你幾乎不能使用STL而不使用指針,因爲它們都是在內部使用指針來實現的。即使你在棧上聲明瞭一個'std :: wofstream',你仍然在使用指針,對吧?我想這裏同樣的事情。 std :: shared_ptr直接使用指針,並間接使用它。 – Anthony
推遲會員在各種情況下的建設很有意義。這裏有幾個方法可以做到這一點;實現之間的差異是由於不同的延期目的。
首次使用初始化;理由:直到需要時才浪費資源。
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
}
};
考慮到OP提到他們的初學C++狀態,讓我指出你必須刪除'loggerStream',可能在LoggerImpl的析構函數中。另外,請參閱我的答案,瞭解如何在指針超出範圍時自動清理指針。 – Anthony
爲什麼不創建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();
}
這是實際回答如何推遲成員構造而不使用指針(以及由堆分配的內存)的唯一文章。 –
「不使用指針」 - 任何理由呢?指針似乎是一個明顯的解決方案。在初始化時顯然會分配它,如果你有任何參考,在任何階段顯然不能爲空。 –
如果它不是一個指針,它將在構建父代的同時被構造;對此你可以做的不多。唯一的另一種選擇叫做兩部分構造,但是這將是'wofstream'類,而不是你的'Logger'類。 –
你爲什麼不想用指針來做這個?有理由嗎? – Netherwire