Rust優(yōu)于C++的兩個(gè)原因 ?
盡管學(xué)習(xí)曲線陡峭,Rust已經(jīng)證明了自己是一門(mén)值得掌握的語(yǔ)言。今天,讓我們深入研究一下Rust優(yōu)于C++語(yǔ)言的原因。
原因1:積極的編譯器優(yōu)化
- Rust的編譯器(LLVM)比C++編譯器更積極地優(yōu)化代碼,這是因?yàn)樗袡?quán)規(guī)則,LLVM可以做出假設(shè)。
- LLVM在內(nèi)聯(lián)函數(shù)方面更加積極,特別是對(duì)于小函數(shù)。內(nèi)聯(lián)避免了函數(shù)調(diào)用開(kāi)銷(xiāo)并使其快速。
例如,下面的函數(shù)可能會(huì)或可能不會(huì)被C++編譯器內(nèi)聯(lián),但LLVM肯定會(huì)內(nèi)聯(lián)它。
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:較低的運(yùn)行時(shí)開(kāi)銷(xiāo)
1,C++棧展開(kāi)導(dǎo)致運(yùn)行緩慢
什么是棧展開(kāi)?
每當(dāng)拋出異常時(shí),在棧上開(kāi)始分配資源和調(diào)用對(duì)象的析構(gòu)函數(shù)的過(guò)程,這稱(chēng)為棧展開(kāi)。
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;
}
棧展開(kāi)是如何工作的?
- 調(diào)用foo()時(shí),它獲取一個(gè)Resource對(duì)象。
- 然后拋出std::runtime_error異常。
- 作為結(jié)果,棧開(kāi)始展開(kāi),并調(diào)用res的析構(gòu)函數(shù)來(lái)釋放Resource。
- 然后,在main()函數(shù)中捕獲異常。
- 這確保了即使在出現(xiàn)異常的情況下也能正確地清理資源。
棧展開(kāi)有運(yùn)行時(shí)開(kāi)銷(xiāo),當(dāng)存在深度嵌套的函數(shù)調(diào)用或具有復(fù)雜析構(gòu)函數(shù)的對(duì)象時(shí),將花費(fèi)時(shí)間來(lái)釋放對(duì)象。
2,Rust使用Result和Option類(lèi)型刪除了的棧展開(kāi)
Rust的Result和Option類(lèi)型用于錯(cuò)誤處理,通過(guò)模式匹配而不是異常來(lái)處理。
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++運(yùn)行時(shí)類(lèi)型信息(RTTI)增加了二進(jìn)制大小和運(yùn)行時(shí)開(kāi)銷(xiāo)
增加二進(jìn)制大小:
運(yùn)行時(shí)類(lèi)型信息(RTTI),RTTI意味著在運(yùn)行時(shí)執(zhí)行動(dòng)態(tài)類(lèi)型檢查和類(lèi)型轉(zhuǎn)換。當(dāng)啟用RTTI時(shí),編譯器在二進(jìn)制文件中包含額外的元數(shù)據(jù)以支持動(dòng)態(tài)類(lèi)型信息。
這些元數(shù)據(jù)通常包括:類(lèi)型信息表(類(lèi)型描述符)、用于動(dòng)態(tài)調(diào)度等的虛函數(shù)表(vtable)。這些表增加了二進(jìn)制文件的大小,特別是對(duì)于具有大量多態(tài)類(lèi)的程序。
增加執(zhí)行時(shí)間:
動(dòng)態(tài)強(qiáng)制轉(zhuǎn)換(dynamic_cast),這包括運(yùn)行時(shí)類(lèi)型檢查,以確保轉(zhuǎn)換的正確性。這種類(lèi)型檢查增加了程序執(zhí)行時(shí)間的開(kāi)銷(xiāo)。
虛函數(shù)調(diào)用,C++語(yǔ)言中的動(dòng)態(tài)多態(tài)性適用于虛函數(shù)調(diào)用,這需要在運(yùn)行時(shí)查找適當(dāng)?shù)暮瘮?shù)。與靜態(tài)調(diào)度相比,會(huì)產(chǎn)生額外的運(yùn)行時(shí)開(kāi)銷(xiāo)。
#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中沒(méi)有RTTI ???
Rust的類(lèi)型系統(tǒng)支持多態(tài)行為和動(dòng)態(tài)分派(基于trait和enum),而不需要RTTI。Box啟用動(dòng)態(tài)分派,不需要運(yùn)行時(shí)類(lèi)型信息。
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上,將高級(jí)結(jié)構(gòu)轉(zhuǎn)換為高效的機(jī)器碼。
Rust優(yōu)于C++的這兩個(gè)原因成立嗎???