Modern C++ - RAII
RAII (Resource Acquisition Is Initialization) 資源取得即初始化,是現代C++的核心思想之一。
RAII保證了任何會訪問該對象的函式中,資源的可用性。
同時它也保證了當對象的生命週期結束時,資源的釋放。
透過RAII,可以保證程序的記憶體安全、異常安全等。
RAII的基本原理
RAII的基本原理是透過作用域來界定對象的生存期,當退出作用域時,意味着對象的生存期結束,對象將被銷毀 (調用它的解構函式)。
根據這一特性,我們就可以在構造函式中初始化資源,並在解構函式中釋放資源來實現RAII自動管理資源的目的。
記憶體&異常安全
RAII實現的對象通常是記憶體安全與異常安全的。
異常發生時,堆棧上的對象會透過解構函式銷毀。因此即便函式提前退出,也能夠保證資源的釋放。
實現RAII
這是一個簡單的範例:
struct Test{
int * data;
Test(int val) {
data = new int(val);// 申請堆上的記憶體
}
~Test() {
delete data;// 釋放記憶體
}
};
int main(){//這是一個作用域,其範圍是該函式的花括號結束。
Test t(1);//在這裏,資源被申請與初始化
{//這是一個作用域,其範圍是該花括號語句結束。
Test t2(2);
}//作用域結束, 對象t2會在這裏調用解構函式,指標data將會被釋放。
}//作用域結束,對象t會在這裏釋放。基於RAII設計的標準庫容器有: string、vector、unique_ptr與shared_ptr等。
open/close、lock/unlock、init/destroy...的類,是典型的非RAII例子。當然,並非所有資源都適合使用RAII,但合理使用RAII不僅可以保證記憶體安全與異常安全,同時也減少了手動資源管理的代碼量,使代碼更簡潔與易維護。
移動語義&RAII
移動語義是C++中,允許將一個資源⌈轉移⌋給另一個資源的的方法。
它透過 右值引用(T&&) 和 move方法實現。
拷貝需要完整複製資源,並且原對象和新對象彼此獨立。
而移動則是轉移資源,避免了拷貝的開銷,對象間產生的冗餘。
在RAII中,移動語義也包括生命週期轉移與所有權轉移的含義。
struct Test{
int * data;
Test(){};
Test(int val) { data = new int(val); }
~Test() { delete data; }
Test(const Test& other) { //拷貝構造函式
data = new int(*other.data); // 深拷貝
}
Test(Test && other) noexcept : data(other.data) { // 移動構造函式
other.data = nullptr; //實現通常建議將原對象的資源置空,避免資源重複釋放。
}
};
int main() {
Test t(1); // t.data的記憶體位址是 0x01。
Test t2 = t; // 拷貝,分配新記憶體,複製數據。現在同時存在0x01和0x02兩份數據。
Test t3 = std::move(t2); //移動,轉移記憶體所有權,t2現在是空的。
//這就完成了所有權的轉移,現在t3擁有了0x02的所有權。且沒有產生任何開銷。
//移動本質上就是將t2.data的指標所有權轉移給了t3.data
//生命週期如何轉移
Test t4;
{
Test t5(2); //記憶體位址0x03,這個變數的生命週期本應在退出作用域時結束。
t4 = std::move(t5); //現在生命週期被綁定到了t4的生命週期。
}
}// t4退出作用域,0x03此時才被釋放。未定義(Undefined behavior)但可解構,其不應再被使用 (即便它可能有效)。未定義行爲表示任何可能,它可能可以按照你的預期運行,可能是一個無用值,或是引發程序崩潰。不少初學者
難以理解的問題,都是因爲使用到了未定義行爲。完整C++移動語義內容:
Modern C++ - Move & 移動構造/C++移動語義
ID:162024-11-23
小結
RAII實現了C++中的自動資源管理,並保證了記憶體安全和異常安全。
同時移動語義可以避免資源間轉移的額外開銷。
它們都是現代C++ 的核心思想與特性之一。
參閱:
你好呀~ 看到留言訊息裏的 ⌈O2⌋可能是拼寫錯誤,故維持了原始網域並更新了頭像路徑 如有誤可再留言變更~
您好,麻烦更新一下我的站点信息,谢谢~ Name: Ethan Desc: Don’t stay awake for too long. Link: https://hanlifeO2.com Avatar: https://hanlifeO2.com/avatar.svg
嗨~ 朋友你好呀,已經加上咯~