Spoiler: C ++ is neither faster nor slower, and generally this is not the point. This article is a continuation of the glorious traditions of debunking the myths of large Russian companies about the Rust language. The previous one was " Go faster than Rust, Mail.Ru Group took measurements ."
Recently, I tried to lure a colleague, a sishnik from a neighboring department, to Darkside of Rust. But my conversation with a colleague did not work out. Because, quote:
In 2019, I was at the C ++ CoreHard conference , listened to Anton's reportantoshkkaPolukhina on the indispensable C ++. According to Anton, Rust is still young, not very fast and not so safe at all.
Anton Polukhin is the representative of Russia in ISO at international meetings of the working group on standardization C ++, the author of several accepted proposals for the standard for the C ++ language. Anton is really a cool and authoritative person in matters of C ++. But the report contains some serious factual errors regarding Rust. Let's take them apart.
We are talking about this report from 13:00 to 22:35 .
Table of contents
β1. Rust C++.
(link:godbolt):
(13:35):
. ! . C++ Rust .
, , . , , . , Rust [-2147483648, 2147483647], C++ [-46340, 46340]. ? ?
-46340 46340 β , std::int32_t
. - signed overflow. , PVS-Studio. , , CI , :
runtime error: signed integer overflow: 46341 * 46341 cannot be represented in type 'int'
runtime error: signed integer overflow: -46341 * -46341 cannot be represented in type 'int'
Rust .
, (13:58):
, C++ . . C++ . Rust' , . . Rust' , , , . , , Rust . - .
, Rust, , Rust LLVM β , Clang. , Rust «» C++ . , , . C++ . .
, int'a:
unsigned MAX_INT = 2147483647;
int hash_code(std::string x) {
int h = 13;
for (unsigned i = 0; i < 3; i++) {
h += h * 27752 + x[i];
}
if (h < 0) h += MAX_INT;
return h;
}
, , Β«byeΒ», ( , ) . , , , MAX_INT .
PVS-Studio, . 27752 3 , , , - .
Rust (link:playground):
fn hash_code(x: String) -> i32 {
let mut h = 13i32;
for i in 0..3 {
h += h * 27752 + x.as_bytes()[i] as i32;
}
if h < 0 {
h += i32::max_value();
}
return h;
}
fn main() {
let h = hash_code("bye".to_string());
println!("hash: {}", h);
}
Debug Release , : wrapping*, saturating*, overflowing* checked*.
, .
β , C++ . . , , «» , .
β2. Rust .
(link:godbolt):
(15:15):
Rust' C++ , bar
. -, - . β¦ , Rust , , UB β , , - . - , - . -- .
. - , NOP bar
C++, Rust. LLVM.
LLVM IR , (link:godbolt):
ret i32 undef
β , LLVM.
LLVM 2006 . , , LLVM . , . LLVM 6 llvm.sideeffect, 2019 rustc -Z insert-sideeffect
, llvm.sideeffect
. (link:godbolt). , stable rustc .
C++ , LLVM Rust C.
, , LLVM, : " ". , Rust , , .
β3. Rust .
(16:00):
. Rust. bar
foo
. , Rust : - , . C++ . Rust . - .
(link:godbolt):
Rust , . -ftrapv
C++ -C overflow-checks=on
Rust, . C++ ud2
, "Illegal instruction (core dumped)", Rust core::panicking::panic
, . core::panicking::panic
:
$ ./signed_overflow
thread 'main' panicked at 'attempt to multiply with overflow', signed_overflow.rs:6:12
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
"" , ? x86-64 , 16 , call
8- , . , push rax. Rust, C++(link:godbolt):
C++, Rust , push rbx
. Q.E.D.
, C++ -ftrapv
, . , Rust -C overflow-checks=on
, (link:godbolt) C++, . -ftrapv
gcc 2008 .
β4. Rust C++.
(18:10):
Rust ...
, Rust', . , "" , 17:30(link:godbolt):
, , , β .
2019 CppCon There Are No Zero-cost Abstractions Chandler Carruth. 17:30 - , std::unique_ptr
(link:godbolt). - noexcept
, rvalue , std::move
. Rust . . Rust extern "Rust"
unsafe
, (link:godbolt):
Rust . noexcept
, rvalue std::move
. . , , .
2019 Rust C++ Benchmarks Game. C++ . . .
β5. C β ++ β noop, C β Rust β PAIN!!!!!!!
(18:30):
, Rust , . , , . ++ , . Rust' - .
.
, Rust , , . Starcraft, .
, Rust cargo, . , , . 2020 crates.io 40 000 .
:
# Cargo.toml
[dependencies]
flate2 = "1.0"
cargo . flate2 , miniz, C, Rust. flate2 .
β6. unsafe Rust.
(19:14):
unsafe
Rust', , , .
Rust' .
, unsafe
β , Rust , unsafe
:
- ;
- unsafe ;
- ;
- unsafe ;
union
.
Rust . lifetime-, unsafe
. , , - . You canβt "turn off the borrow checker" in Rust.
unsafe
" , ". , , . , . , malloc
NULL , Rust . , , , malloc
, : " , ; , , ". unsafe
.
β7. Rust .
(19:25):
C++ , , - - , - null . . Rust . - . Rust , , C++.
Microsoft, 70% , Rust . , Rust.
, unsafe
Rust, , β¦ , , . , , Rust .
, , , Rust C++ , Rust . Rust . , unsafe
.
unsafe
:
// Warning: Calling this method with an out-of-bounds index is undefined behavior.
unsafe fn unchecked_get_elem_by_index(elems: &[u8], index: usize) -> u8 {
*elems.get_unchecked(index)
}
slice::get_unchecked
β unsafe
, . get_elem_by_index
, , . unsafe
(link:playground):
// Warning: Calling this method with an out-of-bounds index is undefined behavior.
unsafe fn unchecked_get_elem_by_index(elems: &[u8], index: usize) -> u8 {
*elems.get_unchecked(index)
}
fn main() {
let elems = &[42];
let elem = unsafe { unchecked_get_elem_by_index(elems, 0) };
dbg!(elem);
}
, , . unsafe
.
, unsafe
(link:playground):
// Warning: Calling this method with an out-of-bounds index is undefined behavior.
unsafe fn unchecked_get_elem_by_index(elems: &[u8], index: usize) -> u8 {
*elems.get_unchecked(index)
}
fn get_elem_by_index(elems: &[u8], index: usize) -> Option<u8> {
if index < elems.len() {
let elem = unsafe { unchecked_get_elem_by_index(elems, index) };
Some(elem)
} else {
None
}
}
fn main() {
let elems = &[42];
let elem = get_elem_by_index(elems, 0);
dbg!(&elem);
}
, . , Rust ( slice::get
), , unsafe
Rust . unchecked_get_elem_by_index
, C.
LTO :
. , C(link:godbolt), , Rust.
β8. Rust .
(20:38):
X. . X, , . . . . , X, .
2018 , Rust, , , . , unsafe
safe
, , .
, (), unsafe, , .
, Mutex, RwLock, thread::spawn. . , Rust ; , Mutex , , , . ? .
, . " - C++" , C++, .
However, from recognized experts, I expect balanced coverage of the situation, which, at a minimum, does not contain gross factual errors.
Many thanks to Dmitry Kashitsyn and Alexei Kladov for reviewing the article.