Rust優于C++的兩個原因 ?
盡管學習曲線陡峭,Rust已經證明了自己是一門值得掌握的語言。今天,讓我們深入研究一下Rust優于C++語言的原因。
原因1:積極的編譯器優化
- Rust的編譯器(LLVM)比C++編譯器更積極地優化代碼,這是因為所有權規則,LLVM可以做出假設。
- LLVM在內聯函數方面更加積極,特別是對于小函數。內聯避免了函數調用開銷并使其快速。
例如,下面的函數可能會或可能不會被C++編譯器內聯,但LLVM肯定會內聯它。
fn f(n: i32, dp: &mut Vec<i32>) -> i32 {
let n1 = n as usize;
if dp[n1] != -1 {
return dp[n1];
}
dp[n1] = Self::f(n-1, dp) + Self::f(n-2, dp) + Self::f(n-3, dp);
dp[n1]
}
原因2:較低的運行時開銷
1,C++棧展開導致運行緩慢
什么是棧展開?
每當拋出異常時,在棧上開始分配資源和調用對象的析構函數的過程,這稱為棧展開。
class Resource {
public:
Resource() {
std::cout << "Resource acquired\n";
}
~Resource() {
std::cout << "Resource released\n";
}
};
void foo() {
Resource res; // Resource acquired
throw std::runtime_error("Error in foo");
}
int main() {
try {
foo();
} catch (const std::runtime_error& e) {
std::cerr << "Caught exception: " << e.what() << std::endl;
}
return 0;
}
棧展開是如何工作的?
- 調用foo()時,它獲取一個Resource對象。
- 然后拋出std::runtime_error異常。
- 作為結果,棧開始展開,并調用res的析構函數來釋放Resource。
- 然后,在main()函數中捕獲異常。
- 這確保了即使在出現異常的情況下也能正確地清理資源。
棧展開有運行時開銷,當存在深度嵌套的函數調用或具有復雜析構函數的對象時,將花費時間來釋放對象。
2,Rust使用Result和Option類型刪除了的棧展開
Rust的Result和Option類型用于錯誤處理,通過模式匹配而不是異常來處理。
fn divide(a: i32, b: i32) -> Result {
if b == 0 {
return Err("Division by zero");
}
Ok(a / b)
}
fn main() {
match divide(10, 0) {
Ok(result) => println!("Result: {}", result),
Err(e) => eprintln!("Error: {}", e),
}
}
3,C++運行時類型信息(RTTI)增加了二進制大小和運行時開銷
增加二進制大小:
運行時類型信息(RTTI),RTTI意味著在運行時執行動態類型檢查和類型轉換。當啟用RTTI時,編譯器在二進制文件中包含額外的元數據以支持動態類型信息。
這些元數據通常包括:類型信息表(類型描述符)、用于動態調度等的虛函數表(vtable)。這些表增加了二進制文件的大小,特別是對于具有大量多態類的程序。
增加執行時間:
動態強制轉換(dynamic_cast),這包括運行時類型檢查,以確保轉換的正確性。這種類型檢查增加了程序執行時間的開銷。
虛函數調用,C++語言中的動態多態性適用于虛函數調用,這需要在運行時查找適當的函數。與靜態調度相比,會產生額外的運行時開銷。
#include <iostream>
#include <typeinfo>
class Base {
public:
virtual ~Base() {}
};
class Derived : public Base {};
int main() {
Base* ptr = new Derived();
Derived* derived = dynamic_cast(ptr);
if (derived) {
std::cout << "Dynamic cast successful\n";
} else {
std::cout << "Dynamic cast failed\n";
}
delete ptr;
return 0;
}
4,Rust中沒有RTTI ???
Rust的類型系統支持多態行為和動態分派(基于trait和enum),而不需要RTTI。Box啟用動態分派,不需要運行時類型信息。
trait Printable {
fn print(&self);
}
struct Base;
struct Derived;
impl Printable for Base {
fn print(&self) {
println!("Base");
}
}
impl Printable for Derived {
fn print(&self) {
println!("Derived");
}
}
fn main() {
let base: Box = Box::new(Derived);
base.print();
}
Rust的編譯器建立在LLVM上,將高級結構轉換為高效的機器碼。
Rust優于C++的這兩個原因成立嗎???