2016-10-02 155 views
-1

是否可以在C++中實現既是爲了確保資源安全釋放又是爲了保證資源安全釋放的 和惰性初始化的設計,即只有在真正使用資源時才獲取資源。如何實現RAII +延遲初始化?

我的想法是,只是實現一個懶惰的初始化,而在真正的資源獲取中,使用RAII。

行業慣例如何?

+0

是的,當然這是可能的。至於行業慣例,我並不知道任何此類對象的現有應用程序。 –

+0

@MarkRansom爲什麼沒有這樣的實現?這是不是合理的概念? – athos

+0

沒有必要一起實現這些概念。只需爲你的懶惰對象使用'shared_ptr'或'unique_ptr'。 –

回答

1

是的,這是可能的。只需使用std::optional(C++ 17或從Boost)或unique_ptr/shared_ptr

(意見)optional在可讀性方面有很大的優勢 - 你不能更清楚地知道這個值可能沒有被初始化。

要顯示資源被正確地釋放:首先讓我們開始渴望初始化(live):

ofstream file("test.txt"); 
file << "no flush\n"; 

ifstream inFile("test.txt"); 
string line; 
getline(inFile, line); 
cout << line << endl; 

這,不打印的me¹什麼。讓我們繼續寫一個單獨的範圍(live):

{ 
    ofstream file("test.txt"); 
    file << "no flush\n"; 
} 

ifstream inFile("test.txt"); 
string line; 
getline(inFile, line); 
cout << line << endl; 

這應該打印no flush,因爲ofstream是保證close()破壞後的文件。 (除非別的東西在同一時間訪問test.txt

而且現在Boost.Optional和延遲初始化(live):

{ 
    boost::optional<std::ofstream> file; 

    file = ofstream("test.txt"); 
    file.get() << "no flush\n"; 
} 

ifstream inFile("test.txt"); 
string line; 
getline(inFile, line); 
cout << line << endl; 

資源都在同一時間發佈的,因爲他們是定期ofstream

¹文件訪問不保證被緩衝,但它是一個很好的例子,也可以在線編譯器上使用。

+0

thx解釋概念,讀取任何代碼片段? @krzaq – athos

+0

我會在一瞬間添加一些東西 – krzaq

+0

thx!想看看輪子是如何製造的 – athos

2

通常的做法是儘量避免懶惰的初始化。

如果有一個懶惰的初始化方案,在實際初始化之前,沒有任何東西阻止對象的調用者(或用戶)執行依賴於初始化對象的事情。這可能會導致混亂。

要應對這種情況,對象(或類)實現需要跟蹤對象是否實際初始化。這使得類的實現更加複雜 - 如果任何成員函數忘記檢查對象是否被初始化,或者任何成員函數將對象置於無效狀態,那麼就可能出現混亂。如果對象(或類)不這樣做,則該類很難使用,因爲使用該類的代碼的任何錯誤都會導致問題。 (1)構造函數建立一個不變的(2)成員函數,假設保持不變和(3)析構函數清理。

換句話說,構造函數初始化對象,成員函數確保對象保持合理狀態。允許成員函數在被調用時假設對象處於有效狀態....因此不需要檢查。只要所有成員函數確保對象在返回時仍處於有效狀態,就沒有問題。

唯一的例外是析構函數,它會導致對象停止存在。換句話說,在銷燬一個對象(調用其析構函數)之後,根本不應該使用該對象的任何成員。

對於調用者來說,很簡單 - 創建對象之前不要創建對象。換言之,代替

SomeObject object; 

// gather data needed to initialise object 

// Danger, danger: it is possible to mistakenly use object as if it is initialised here 

object.initialise(needed_data); 

// do other things with object 

//object ceases to exist (e.g. end of {} block). 

爲此

// gather data needed to initialise object 

// note that the compiler will reject using object here 

SomeObject object(needed_data); 

// do other things with object 

//object ceases to exist (e.g. end of {} block). 

在C++中,有在需要時創建沒有辦法來防止一個對象。變量不限於在塊的頂部或類似的地方聲明。

+0

因此,在generatl中它是構造函數初始化,以便成員函數可以使用資源,假設它處於valide狀態,直到析構函數清除它,因此不建議執行延遲初始化?但是到處都是懶惰的初始化。我很困惑,這不能成爲C++的特殊練習。你的意思是暴徒是錯誤的,就像人們仍然在使用辛格爾頓一樣(http://www.onelib.org/article/singletons-solving-problems-you-didnt-know-you-never-had-since-1995)? – athos

+0

當然,有些情況下使用惰性初始化。儘管在某些情況下這樣做是有道理的,但其中很多情況僅僅是C的宿醉,在實踐中,創建對象和初始化對象通常都是不同的操作。這種分離在C++中很少需要,因爲使用構造函數創建對象的操作只需一步即可完成(雖然具體是由編譯器來管理)。你問了RAII與懶惰初始化的混合 - 這是懶惰初始化不好的一種情況。 – Peter

+0

感謝您的解釋 – athos