C++ vs Rust

■ このスレッドは過去ログ倉庫に格納されています
2021/04/24(土) 08:04:49.48ID:nPKzA798
競え
2021/04/24(土) 09:03:31.43ID:CqGuC/ho
何で?
2021/04/24(土) 09:10:09.42ID:MAG7Rri7
どちらも変なプライド拗らせたアホしかいない印象
4デフォルトの名無しさん
垢版 |
2021/04/24(土) 10:50:18.68ID:N1eYD/7j
C++: カミソリ
Rust: 安全カミソリ
2021/04/24(土) 11:18:00.79ID:gMqF1SGc
別に〜
裏方一緒だし
2021/04/25(日) 11:37:52.88ID:vJWG11Gh
一概にどちらが優れているとは言えないことではあるが、
代入やコンストラクタが、moveとcopyのどちらになるかについて、Rustの
方が自動化が進んでいると思いがちだが、実際は、
C++は、関数の戻り値が構造体型/クラス型になっている場合に関しては
RVO(Return Value Optimization)が働き、右辺が
クラス名(実引数列)
の形式の一時オブジェクトである場合には、moveが選ばれるが、それ以外は、
概ねcopyになるので、ある意味では「自動選択」しているのに対し、
Rustでは、x = y と書いた場合、原則的には「デフォルトmove」の規則に
従い、copyしたい場合は、右辺をy.clone()と書くことになっていて、
「手動選択」を採用している。
C++は、どう書いた場合にmoveになり、どう書いた場合にcopyになるかを全て把握するのは
難しくて、C++の仕様が勉強不足だと勘違いや見落としが発生する可能性があるのに対し、
Rust方式は、moveとcopyのどちらになるかが明確なので混乱が少ないと言えるかも知れない。
つまり、このことに関しては、児童選択より手動選択の方が安心感があるかも知れない。
意見を求む。
2021/04/25(日) 11:57:11.84ID:Ef2Yns/P
Copy trait実装してたら暗黙的に実行されるわ。
とはいえc++のそれよりかは分かり易いけど。
2021/04/25(日) 13:18:15.15ID:rtrHqrCb
[C++]
xやfunc()の戻り値が CPerson というクラス型の場合、
10. x = y; // copy代入。yの中味はxにコピーされる。yのデータも保存。
11. x = std::move(y) // move代入。yのデータは破棄される。
12. x = func(a); // move代入または、RVOが働いてmove代入以上に速い動作になる。
          関数の戻り値だけは特別に処理されている。

[Rust]
(CPerson がCopy traitを実装して無い場合に限定)
20. x = y; // move。以後、y は使用できなくなる。これが故にデフォルトmoveと呼ばれる。
21. x = y.clone(); // copy。以後もyは使用できる。
22. x = func(a); // move。20.と同じ規則に従っているだけで関数の戻り値だから特別では無い。

C++の場合、12.で関数だけは特別処理されているのに対し、Rustの22では
関数でも特別処理されているわけではなく、20.のデフォルトmoveの原則に従っているだけ
のように見える。
C++の場合、11. では、std::move()で修飾すると、なぜか、10. で修飾しなかった場合
より、実行されるCPUの処理が「減る」。ソースコードで関数の様なものを
追加した方が追加しなかったときよりCPUの処理が減ってしまうのは、どことなく直感に
反する。
一方、Rustの21と20を比較すると、.clone()を書いた方が書かなかったときより、
実行されるCPUの処理が増えるので、直感的である。
この場合、.clone()を書いたことで「コピーするためにCPUの処理が追加された」という
直感に沿った感じになるから。
C++の場合、std::move()と書くと「std::move()という関数の様なものを書いたのに、
なぜか、CPUの処理が減る」という違和感を感じるようになる。
2021/04/25(日) 17:13:07.94ID:In1fvQYU
要はRustの代入ってmemcpyで、単純なmemcpyされると困るデータ(!Copy)の場合右辺がinvalidate(move)され使えなくなる
って理解がシンプルなのかな
2021/04/25(日) 18:00:12.34ID:S2tV53BX
>>9
x = y の時、
結果的にはほとんどmemcpy(&x,&y,サイズ)に近い動作になっているかもしれないな。
ただ、右辺yの構造体メンバの中にRc<T>のような複雑なものが入っている場合、
結果は単純コピーのようになったとしても、コンパイラはもっと丁寧に処理
しているのではなかろうか。
2021/04/26(月) 01:44:08.26ID:+85I2LX6
>>10
move は memcpy だよ
Rc も実体はヒープへのポインタだから memcpy で問題ない
memcpy してはいけない例としては async fn みたいな自己参照構造体などがあるけど
Pin をうまく使うことで変な状態にならないようにしている
12デフォルトの名無しさん
垢版 |
2021/04/26(月) 17:23:54.42ID:92SW7900
c++に批判的な姿勢で知られるlinusがなぜrustにはwelcomeな態度取ってるのかが理解できない
rustだってメモリ安全性がなければc++みたいなもんだろ
2021/04/26(月) 17:27:49.70ID:oHxAx7LN
言うほどwelcomeか?
14デフォルトの名無しさん
垢版 |
2021/04/26(月) 17:29:26.57ID:92SW7900
>>13
貶すまではいってないじゃん
15デフォルトの名無しさん
垢版 |
2021/04/26(月) 18:48:21.42ID:pZ6mft9e
あわしろ氏もRustは凄いって言ってましたね。
C++をあまり好きじゃないところも同じ。
2021/04/26(月) 20:08:40.47ID:cN+lbm0F
>>12
c++にもだいぶ甘くはなってるよ。
ただそれでもrustに対してもそこまで容認的ではない。
試しにドライバー書いてみれば?って言って試させてるが、まだまともには考えてないわ。
https://lkml.org/lkml/2021/4/16/901
17デフォルトの名無しさん
垢版 |
2021/04/26(月) 20:27:04.95ID:92SW7900
>>16
むしをrust側に対して例外処理の方法をカーネル内での往来の方法に変更してくれって促しているように見えるんだけど
導入したがってるやんけ
2021/04/26(月) 20:51:20.12ID:cN+lbm0F
>>17
続きを読めば?どういう流れかわかるから。
19デフォルトの名無しさん
垢版 |
2021/04/26(月) 21:27:22.23ID:92SW7900
>>18
続きで懐疑的な立場取ってんのlinusじゃなくね?
2021/04/26(月) 22:53:32.32ID:cN+lbm0F
>>19
話の流れは大体予想できてただろうなという受け答えだろ。
んでもって実際、発案者自らmoonshot言うとるわ。
少しは内容を読んでくれ、なんで一から十まで説明しなきゃならんのか。
21デフォルトの名無しさん
垢版 |
2021/04/26(月) 23:32:00.78ID:92SW7900
>>20
じゃあレスすんなよカス
2021/04/26(月) 23:47:01.17ID:cN+lbm0F
だから読めって。。文盲なんか?
2021/04/27(火) 00:14:36.96ID:H90KgUtd
>>20
moonshotって言ってるの割り込みコンテキストでallocator呼び出すことをコンパイル時にチェックできるようにしたいという話では
現実的には関数ごとにどのコンテキストで呼び出せるものなのかタグ付けしてるとかなんとか
綺麗じゃないけど、まあ動くわなという解決策

つまみ食いしかしてないから読み違えてるかも知れないけど
これをもってlinuxカーネルにrust取り込むのを否定するような話ではないようにみえた

他にもmoonshotって言ってる箇所ある?
2021/04/27(火) 01:12:51.08ID:VJIOoOWO
一通り読んだけど他にmoonshotって言ってるとこはなかったような。
2021/04/27(火) 08:00:23.09ID:/+bIFNU8
>>23
あのね。。書けばそうなるってものじゃなくてそれを実装しなきゃならんのよ。。
コンパイラにそういったコンテクストを判断させるのがめちゃくちゃ難しいっていってるでしょ?
なんでそんなに読み取れないの?
26デフォルトの名無しさん
垢版 |
2021/04/27(火) 15:37:12.22ID:Nn42Sot0
>>25
当面はdoc commentにannotation書いて済ませておくって言ってるやん
何はともあれ大局的にはrustをlinux kernelに取り込む方向へ進んでいくことには間違いない
2021/04/27(火) 16:10:45.63ID:/+bIFNU8
>>26
だからそのコードじゃpanic捉えきれねーからカーネルに入れるわけねーだろって
言ってんじゃん。。何読んでんだよ。
2021/04/27(火) 18:23:48.67ID:n/AWrch2
まあ半年後どうなるかで誰が正しかったかは分かるわな
2021/04/27(火) 20:32:29.92ID:/+bIFNU8
半年も経たなくてももうわかってるっつーの。。だからちゃんと英語の勉強しましょうね。
2021/04/28(水) 03:52:50.81ID:v8E9sca8
C++で、n要素のint型の生配列を確保するには、
int *pBuf = new int [n];
だけど、Rustの
let a:Box<i32> = Box::new<x>;
値が x である 32BIT 整数を Heap に 1 つ確保する、という意味だよね?
Heapに n 要素の i32 型の配列を確保したい場合、
let a:Vec<i32> = vec![0; n];
かな?
2021/04/28(水) 03:55:12.80ID:v8E9sca8
>>30
あ、
let a:Box<i32> = Box::new<x>;
ではなく、
let a:Box<i32> = Box::new(x);
let a:Box<i32> = Box<i32>::new(x);
let a = Box::new(x);
let a = Box<i32>::new(x);
かな。
2021/04/28(水) 04:01:18.27ID:v8E9sca8
>>31
確保した領域の中身を書き換えたい場合は「mut」を付ける必要があり、
値が x である 32BIT 整数を Heap に 1 つ確保するのは:
let mut a:Box<i32> = Box::new(x);
let mut a:Box<i32> = Box<i32>::new(x);
let mut a = Box::new(x);
let mut a = Box<i32>::new(x);
のどれかの書き方で、Heapに n 要素の i32 型の配列を確保するのが、
let mut a:Vec<i32> = vec![0; n];
let mut a = vec![0; n];
のどちらかの書き方かな?
2021/04/28(水) 10:37:51.57ID:6K8rF/jG
let mut a = Box::new([0,n]);
2021/04/28(水) 12:44:00.99ID:jQpDsyge
>>33
なるほど、そんな書き方があったとは。でも正しくは、
let mut a = Box::new([0; n]);
かな?
2021/04/28(水) 15:21:28.78ID:jQpDsyge
[0; n]
って、n 要素のi32配列を確保して0で初期化するという意味らしいけど、
nは実行時に決まらないような変数も指定できるの?
2021/04/28(水) 16:30:39.18ID:BfdKSrwu
>>35
できない

https://stackoverflow.com/questions/41710952/allocate-array-onto-heap-with-size-known-at-runtime

Vec<i32>に相当するのはstd::vector<int>だから、
>>33はstd::unique_ptr<int []>相当のBox<[i32]>型の例を出そうとしたのだろう
そういう値は作れるが、Box::newでは無理
37デフォルトの名無しさん
垢版 |
2021/08/31(火) 15:22:27.39ID:8qO1h2Cp
246 デフォルトの名無しさん sage 2021/08/31(火) 14:25:42.76 ID:SlncBcTV
>>244
ポインタは適切に使えばデータ構造やアルゴリズム自体が根本的に変えることが
できるので使わない時と比べて計算オーダー自体が劇的に変化することがあり、
プラシーボではない。
Rustはその点でC/C++に勝てない事がある。

247 デフォルトの名無しさん sage 2021/08/31(火) 14:28:10.16 ID:SlncBcTV
例えば、動的配列であるところのVectorはポインタでアクセスしても余り
効率は良くならないが、LinkedListは構造的にポインタで連結されており、
首尾一貫して添え字アクセスを使わずに必ずポインタでノードを識別する
ようにすれば、Vectorに比べて劇的に効率アップできることがある。
それはRustではほぼ不可能。ベンチマークはこの点が反映されてない。
2021/08/31(火) 16:19:11.51ID:KWeLtswn
コード例と性能測定結果くれ
2021/08/31(火) 17:18:36.26ID:SlncBcTV
>>38
同じ動作をしてもVectorだとO(N)なのに、LinkedListだとO(1)になるものがある。
これだけでも実験してみなくてもNが大きくなった時に明らかに速度が
違うことはコンピュータ科学では常識。
例えば、コロナの感染者数は、O(exp(aN))になるので、どんだけ頑張っても、
Nが十分大きい時にはO(N^b)が上回ることは出来ない。
2021/08/31(火) 18:26:05.32ID:8qO1h2Cp
まだstable入りはしてないけどlinked_list::{Cursor, CursorMut}っていうのがあるね
そのベンチマークでは使ってる?
2021/08/31(火) 19:03:52.76ID:WFW0JNLV
LinkedListとはなんぞや?std::list?
2021/08/31(火) 19:52:34.92ID:4dUmDNFP
>>39
Rust は stable で LinkedList も VecDeque (双方向キュー)もありますよ
https://doc.rust-lang.org/std/collections/index.html
ここにそれらのオーダーが O(1) や O(N) になる話もまとまっています
2021/08/31(火) 21:21:08.46ID:KWeLtswn
>>39
参照局所性の問題もあるから計算量の理論通りにはいかない場合もあるけど、ちゃんと性能測定してデータ構造選定した?
2021/08/31(火) 21:26:21.55ID:KWeLtswn
あとRustではほぼ不可能の意味が分からない
Rust にはポインタがあるから C や C++ のデータ構造はほぼ実現可能なのでは
2021/08/31(火) 22:08:35.31
>>44
では赤黒木をひとつやってみて
2021/08/31(火) 22:27:32.77ID:wvWDiazC
>>45
Rc<RefCell<Node>>のパターン
Safe Rustでも実現可能
2021/08/31(火) 23:58:27.88ID:SlncBcTV
>>42
ところが、Rustでは借用規則のせいで上手く行かない。
めんどくさいので自分で気づく人だけが理解してくれればいいので、
俺はこれ以上説明しない。
理解できない人は、親切な人が説明してくれるのを待て。
2021/08/31(火) 23:58:51.57ID:SlncBcTV
>>44
無理。
2021/09/01(水) 00:55:38.60ID:MtyAaHfZ
>>47
それはあなたが無知なだけだ
Rustはメモリ安全性を保証する
一方でRustの標準ライブラリではunsafeが多数使われているがこれはメモリ安全性を保証できる操作を効率よく実装するためにある
つまり論理的にメモリ安全性を保証できるならばunsafeを用いてもそれをライブラリやモジュールに閉じ込めることができる
もちろん自作でもこれは同様である
新たな型も当然作ることが可能
標準ライブラリで提供されているリンクドリスト型や双方向リスト型はそのようにして作られている
つまり効率をも落とさない
2021/09/01(水) 01:25:17.04ID:+dwouIiT
>>49
お前は何も分かってない。
馬鹿は黙ってろ。
2021/09/01(水) 01:27:41.34ID:FA803rPU
>>40にも答えてくれよ
その「問題」とやらはCursorじゃ解決されてないのかい
52デフォルトの名無しさん
垢版 |
2021/09/03(金) 08:12:39.26ID:t+NhPRD1
>>49
ガイジ
2021/09/07(火) 20:33:21.38ID:ezLxFpG4
結局unsafe多用するとか意味ないジャンw
54デフォルトの名無しさん
垢版 |
2021/09/07(火) 23:30:30.79ID:W5eU3b0C
>>53 裏方のunsafeなコード(≠危険なコード)を安全に利用してプログラムを書けるのがRustだと思う
また、その裏方のunsafeなコードをRustで書く意味はRustから扱いやすいこと、Rustプログラマーが慣れたRustの文法で書けることがあると思う
2021/09/08(水) 01:30:18.74ID:c9lCkxrV
>>54
お前の理解は浅くて、間違っている。
お前の様な数学の出来ない人には何を言っても無駄。
2021/09/08(水) 01:30:55.64ID:c9lCkxrV
unsafeを閉じ込め切れるならRustはパーフェクトだが、そうはなってないのだ。
57デフォルトの名無しさん
垢版 |
2021/09/08(水) 09:53:24.22ID:8gtworgR
>>55 そうか、まぁ一個人の感想ぐらいに受け取ってくれ
58デフォルトの名無しさん
垢版 |
2021/09/09(木) 16:53:30.53ID:lJRSMQ7p
なんだかんだ言ってまだまだC++だな
2021/09/09(木) 17:22:38.75ID:fa/WJTRs
unsafe を閉じこめられるかどうかはAPI設計力が問われるよな
2021/09/09(木) 18:17:29.61ID:18O2MBOf
>>56
Rustはunsafeを局所的に安全に閉じ込めることができます
例えばVec<T>型はその各メソッド実装においてunsafeを用いています
これも『Rustがunsafeを局所的に安全に閉じ込めることができる』具体的な実例です

>>58
C++よりもRustの方が優れています
2021/09/10(金) 08:39:25.32ID:w07MHOd0
>>60
前半、数学的には間違い。
お前には数学の才能が無い。
2021/09/10(金) 09:06:15.40ID:Ga+Uz44a
数学関係ないし
お前には数学の才能が無い
2021/09/10(金) 09:26:50.69ID:XIGB6bHM
数学的に間違いの意味がようわからんが、
unsafeブロック内あるいは関数内でSAFETYが守られるようにしないと安全に閉じ込めることができないって意味??
2021/09/10(金) 09:28:15.95ID:KDfyX1FH
Vec<T> が unsafe を使って安全なインターフェースを提供してることへの反論を示してくれ
2021/09/10(金) 11:00:27.70ID:4cVpX4oe
>>63
そうでなくて、unsafeブロックで閉じ込めようとしても、閉じ込め切れなくて、
O(x)で表される計算時間が、C言語とは同じでは絶対に不可能な場合があるんだ。
Rustのsafeモードでは、コンテナの中のノードに対して書き込み参照と読み込み参照
を持つことが借用規則によって禁じられていることが原因。
C言語ではそれが当たり前に出来るからとても効率の良いプログラムが可能だが
Rustでは、unsafeの外側ではそれが出来ないから不可能だ。
アプリレベルでそれが出来ないから。
これで納得できない人は数学の才能が無い。
俺は数学の天才。
2021/09/10(金) 11:05:19.78ID:4cVpX4oe
>>65
数学の才能が無い人のためにもう少し詳しく書いてやろう。
・Rustのsafeモードでは、LinkedListの中の複数のノードに対して、
 読み込み参照と書き込み参照を一度自動時には持てない。
 持つと borrow cheker がコンパイル時にエラーを出してしまう。
・C言語ではそれが当たり前に出来る。
・アプリレベルで1つのLinkedListに対して複数の読み込み参照と
 書き込み参照を同時に記録し続けることで、やっと、挿入や削除が
 O(1)になる。index 値で保持すると O(N)になってしまうから、
 vector と同じ速度オーダーしか出ない(つまり、LinkedList本来の性能
 が全く出せない。)
・結果、Rustは、Cより遅いプログラムしか出来ない。その遅さは、データが
 多いとき、C言語に比べて1万倍でも100万倍でも遅くなる。
2021/09/10(金) 11:27:11.50ID:2Djs9W2b
>>66
コードで書いて
2021/09/10(金) 11:30:01.67ID:4cVpX4oe
>>67
RustとCの知識と、東大数学が簡単に解けるような数学の才能をすべてもっている人
に聴いてみろ。
2021/09/10(金) 11:36:42.07ID:4cVpX4oe
>>68
本当は次のような知識も必要:
・リンクドリストの構造。
・リンクドリストの挿入、削除などの計算オーダーO(x)。
・計算オーダーの記号O(x)の意味。ビッグオー。ランダウの記号。
 東大、京大の学部レベルの解析学(微分積分学)の本を見よ。
・index 値 = 基本は配列の添え字。0から割り振られた連番。
 リンクドリストでは本来使わないが、Rustではノードの場所を覚えておくために
 使わざると得ない。その場合、リンクドリストの先頭のノードを 0 番とし、
 次のノードを 1, その次のノードを 2 のように表す。
 しかしそうすると、リンクドリスとの M 番目の場所の参照を取得するのに
 O(M)の時間が掛かってしまい、リンクドリストの効率の良さが台無しになってしまう。
・このことから、リンクドリストが遅いという誤解を生む状況になってしまっている。
2021/09/10(金) 11:38:10.81ID:2Djs9W2b
>>68
東大数学って何?
2021/09/10(金) 11:39:59.60ID:4cVpX4oe
>>70
高校生が灯台に入学するときに受ける東大の数学の試験のことだよ。
それが簡単に解けるくらいのやつに聞いてみろって事だ。
しかし、受験テクニックやパターン学習によって解ける様になったやつはダメだ。
2021/09/10(金) 11:49:52.37ID:2Djs9W2b
>>69
O(1) で i 番目の要素にアクセスできる safe な LinkedList 実装はある
https://docs.rs/chainlink/0.1.0/chainlink/struct.LinkedList.html
2021/09/10(金) 11:52:48.63ID:2Djs9W2b
>>72
i 番目の要素というと不正確か
ポインタの代わりに Arena 内での index を使うことで LinkedList のノードを O(1) で参照することができる
2021/09/10(金) 11:53:08.66ID:FsmeH+FF
https://play.rust-lang.org/?version=nightly&;mode=debug&edition=2018&gist=bc6e823f6a44e442aabd4d4882d3eb5a

Repeated 1 time(s), duration = 2.531µs
Repeated 10 time(s), duration = 4.661µs
Repeated 100 time(s), duration = 29.449µs
Repeated 1000 time(s), duration = 256.555µs
Repeated 10000 time(s), duration = 1.800129ms
Repeated 20000 time(s), duration = 3.273489ms
Repeated 50000 time(s), duration = 8.345219ms
Repeated 100000 time(s), duration = 16.454731ms
Repeated 200000 time(s), duration = 32.911471ms
Repeated 500000 time(s), duration = 83.993118ms
Repeated 1000000 time(s), duration = 166.193956ms

結構実行毎にゆれる感じはあるけど、おおむねO(1)じゃないですかね
2021/09/10(金) 12:09:20.46ID:4cVpX4oe
>>74
アホですか?

>>73
Arenaを使った時点で裸のリンクリストじゃ無いし、時間は、O(x)が同じでも
オーバーヘッドが発生する。また、無駄なメモリー領域も食う。
2021/09/10(金) 12:12:17.45ID:Ga+Uz44a
>>68
呼んだ?
2021/09/10(金) 12:14:53.57ID:Ga+Uz44a
>>71
えっ?
高校数学?
レベル低くないか?
2021/09/10(金) 12:18:15.36ID:Ga+Uz44a
少なくとも>>65が書いてることは数学的でも何でもない
2021/09/10(金) 12:18:20.87ID:FsmeH+FF
>>75
はい、私はアホで数学の才能が無いので数学の天才様の問題意識が分かりません
VecならO(n)になる先頭への挿入がO(1)でできることを示したつもりでしたが見当違いでしたでしょうか
■ このスレッドは過去ログ倉庫に格納されています
5ちゃんねるの広告が気に入らない場合は、こちらをクリックしてください。

ニューススポーツなんでも実況