スマートポインターボックスの謎を解明

スマートポインターボックスの謎を解明

[[416792]]

この記事は、董澤潤氏が執筆したWeChat公開アカウント「董澤潤の技術ノート」から転載したものです。この記事を転載する場合は、Dong Zerun の Technical Notes 公開アカウントにご連絡ください。

C++に精通している人はshared_ptr、unique_ptrを知っているはずです。また、RustにはスマートポインタBox、Rc、Arc、RefCellなどがあります。この記事では、Boxの基礎となる実装を紹介します。

<T> はヒープ上にスペースを割り当て、T 値を格納し、対応するポインターを返します。同時に、Box は Deref 逆参照と Drop 破壊の特性も実装しており、Box がスコープを離れるときに自動的にスペースを解放します。

入門例

この例は Rust の本から引用したものです。デモンストレーションの目的で、print ステートメントは削除されています。

  1. メイン関数(){
  2. _ = Box::new(0x11223344); とします。
  3. }

変数 0x11223344 をヒープ上に割り当てる、いわゆるボクシングですが、Java の学習者ならよく知っているはずです。 dockerをマウントし、rust-gdbを使用してアセンブリ実装を表示してみましょう。

  1. アセンブラコードダンプ 関数hello_cargo::main:
  2. 0x000055555555bdb0 <+0>: サブ $0x18、%rsp
  3. 0x000055555555bdb4 <+4>: 移動 $0x11223344,0x14(%rsp)
  4. => 0x000055555555bdbc <+12>: 移動 $0x4,%esi
  5. 0x000055555555bdc1 <+17>: 移動 %rsi,%rdi
  6. 0x000055555555bdc4 <+20>: callq 0x55555555b5b0 <alloc::alloc::exchange_malloc>
  7. 0x000055555555bdc9 <+25>: 移動 %rax,%rcx
  8. 0x000055555555bdcc <+28>: 移動 %rcx,%rax
  9. 0x000055555555bdcf <+31>: 移動 $0x11223344、(%rcx)
  10. 0x000055555555bdd5 <+37>: 移動 %rax,0x8(%rsp)
  11. 0x000055555555bdda <+42>: lea 0x8(%rsp),%rdi
  12. 0x000055555555bddf <+47>: callq 0x55555555bd20 <core::ptr::drop_in_place<alloc::boxed::Box<i32>>>
  13. 0x000055555555bde4 <+52>: $0x18,%rspを追加
  14. 0x000055555555bde8 <+56>: 戻り値
  15. 終わり アセンブラダンプ

重要なポイントは 2 つあります。alloc::alloc::exchange_malloc はヒープ上にメモリ領域を割り当て、この malloc のアドレスに 0x11223344 を格納します。

関数の最後では、コンパイラは型が alloc::boxed::Box であることを認識しているため、アドレスは core::ptr::drop_in_place に渡されて解放されます。は、Boxの対応するドロップ機能を使用します

この例だけを見ると、Box は不思議ではありません。対応するアセンブリ実装は、通常のポインタと何ら変わりありません。すべての制約はコンパイル時の動作です。

所有

  1. メイン関数(){
  2. x = Box::new(String:: from ( "Rust" ));
  3. y = *x とします。
  4. println!( "x は {} です" , x);
  5. }

この例では、文字列はボックス化されていますが、String は広い意味でスマート ポインターであるため、ボックス化する必要はありません。この例ではエラーが報告されます

  1. 3 | y = *x とします。
  2. | -- 値がここに移動されました 
  3. 4 | println!( "x は {} です" , x);
  4. | ^以降は借用した値 動く 

*xはStringに逆参照され、yに割り当てられると移動セマンティクスが実行され、所有権がなくなるため、後続のprintlnはxを印刷できません。

  1. y = &*x; とします。

これを修正するには、文字列への不変の参照を取得します。

低レベルの実装

  1. pub構造体ボックス<
  2. T: ?サイズ、
  3. #[unstable(feature = "allocator_api" , issue = "32838" )] A: Allocator = Global
  4. >(ユニーク<T>, A);

上記は Box の定義です。これは 2 つのジェネリック パラメータを持つタプル構造であることがわかります。T は任意の型を表し、A はメモリ アロケータを表します。 A は標準ライブラリの Gloal のデフォルト値です。 T にはジェネリック制約 ?Sized があり、これは型のサイズがコンパイル時にわかる場合とわからない場合があることを意味します。もちろん、これは通常、サイズが不明なシナリオで使用され、上記のように int を格納することはほとんどありません。

  1. #[stable(feature = "rust1" 、 since = "1.0.0" )]
  2. 安全でない実装<#[may_dangle] T: ?Sized, A: Allocator>ドロップ  Box<T, A>の場合{
  3. fnドロップ(&mut 自己) {
  4. // FIXME: 何もせず、ドロップする 現在はコンパイラによって実行されています
  5. }
  6. }

これはDrop実装であり、ソースコードにも記載されており、コンパイラによって実装されています。

  1. #[stable(feature = "rust1" , since = "1.0.0" )]
  2. Box<T, A> の<T : ?Sized, A: Allocator> 参照実装 {
  3. タイプ ターゲット = T;
  4.  
  5. deref(&self) -> &T {
  6. &**自己
  7. }
  8. }
  9.  
  10. #[stable(feature = "rust1" , since = "1.0.0" )]
  11. impl<T: ?Sized, A: Allocator> Box<T, A>DerefMut {
  12. deref_mut(&mut self) -> &mut T {
  13. &mut **自分自身
  14. }
  15. }

逆参照動作を定義するために Deref を実装し、可変逆参照のために DerefMut を実装しました。したがって、*xは*(x.deref())という演算に対応する。

適用可能なシナリオ

公式サイトでは以下の3つのシナリオが挙げられています。本質的にはBoxは通常のポインタとあまり変わらないので、Rc、Arc、RefCellほど便利ではありません。

  • コンパイル時に型のサイズが不明であるが、コードシナリオでは型のサイズの確認が必要な場合
  • 大量のデータがあり、データをコピーせずに所有権を移動する必要がある場合
  • 特性オブジェクト、または dyn 動的配布は、コレクション内に異なる型を格納したり、異なる型をパラメーターとして指定したりするためによく使用されます。

公式サイトにはリンクリストの実装がある

  1. 列挙型リスト{
  2. Cons(i32, リスト)、
  3. ゼロ、
  4. }

上記のコードは実行できませんが、その理由は非常に単純です。これは再帰的な定義です。対応する C コードも受け入れられません。通常、次の型をポインターとして定義する必要があります。

  1. 列挙型リスト{
  2. Cons(i32, ボックス<リスト>)、
  3. ゼロ、
  4. }
  5.  
  6. crate::List::{Cons, Nil} を使用します。
  7.  
  8. メイン関数(){
  9. リストを Cons(1, Box::new(Cons(2, Box::new(Cons(3, Box::new(Nil)))))); とします。
  10. }

公式サイトで提示されている解決策は、次をポインターボックスに変えることですそれは常識であり、言うべきことはあまりない

<<:  米国の刑務所、受刑者の通話を分析するために人工知能を導入する計画

>>:  日本メディア:中国は人工知能の分野で米国を追い越している

ブログ    
ブログ    
ブログ    

推薦する

AIは新たな科学革命を先導している

この記事はLeiphone.comから転載したものです。転載する場合は、Leiphone.com公式...

回答 2024: 生成 AI は「スーパー アプリ」になるか?

ゲスト: 陳斌、黄文馨ホスト | ユン・チャオノア著制作:51CTO テクノロジースタック(WeCh...

...

「スマートストア」のAIカメラは何ができるのか?

スマートシティが理論的な概念から正式な計画と建設へと進化するにつれて、スマートストアはスマートシティ...

チューリング賞受賞者:人工知能を実装したものは、もはや人工知能とは呼ばれない

1956年、マッカーシーはダートマス大学で開催された会議で初めて「人工知能」の概念を提唱した。後に、...

...

清華大学が世界初のオンチップ学習メモリスタメモリコンピューティング統合チップを開発、その成果がサイエンス誌に掲載された。

10月9日、清華大学の公式Weiboアカウントは、オンチップ学習をサポートする世界初のメモリスタス...

機械学習による分類とその応用を理解するための図

機械学習は主に教師あり学習、教師なし学習、強化学習に分けられます。ただし、各手法の適用分野はそれぞれ...

...

...

...

機械学習の仕事を探すとき、学歴はどの程度重要ですか?

[[254426]]機械学習の分野における知識とツールの主な特徴は、無料かつオープンであることです...

AIの4つのタイプについてお話しましょう

人工知能が流行するにつれ、人々はそれがどのように機能し、何ができるのかについて多くの疑問を抱いていま...

GenAI Security: Microsoft Copilot でデータ侵害を防ぐ方法

Microsoft の Copilot は、世界で最も強力な生産性向上ツールの 1 つと言われていま...

これら15のアルゴリズムをマスターすれば、グラフデータベースNeo4jを操作できるようになります。

チャート分析はビジネス上の意思決定において非常に価値があり、優れたグラフ アルゴリズムは使いやすく実...