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

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

[[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. }

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

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

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

ブログ    
ブログ    
ブログ    

推薦する

十八龍掌:トランスフォーマーのメモリ使用量を最適化するこのスキルの組み合わせは、収集する価値があります

ビジョントランスフォーマーや LLM などのディープラーニングモデルをトレーニングする場合、ピーク時...

5G車道協調自動運転技術の応用について解説した記事

自動運転は現在社会的なホットな話題となっており、人工知能と自動化技術の革新的な開発にとって重要な方向...

人工知能翻訳は、障害なく外国人と恋に落ちるのに役立ちます

AI 音声翻訳の分野では、ノイズは対処しなければならない主要な課題の 1 つです。この装置は研究室や...

生成 AI は現在の DevOps および SRE 作業システムをどのようにサポートしますか?

こんにちは、ルガです。今日は、人工知能エコシステムの中核技術である「生成型人工知能」を意味する GA...

機械学習を実装するには?

機械学習の実装は、AI を活用した製品やサービスの成功にとって重要なステップです。 MLOps が企...

...

脳コンピューターインターフェース技術における大きな進歩!麻痺した男性が初めて運動と触覚を取り戻す

[[324403]]図1:2010年に重度の脊髄損傷を負った後、バークハートは運動皮質にマイクロチッ...

ニューラル ネットワークはなぜ任意の関数を近似できるのでしょうか?

この記事では、主にニューラル ネットワークの普遍近似理論を紹介し、PyTorch を使用して 2 つ...

NVIDIA は、わずか 5 行のコードで画像を 3D モデルに変換する 3D ディープラーニング ツール Kaolin をリリースしました。

近年、3D コンピューター ビジョンと人工知能はともに急速に進歩していますが、両者の効果的な組み合わ...

AIは中所得層に影響を与えるでしょうか?周連:移行の痛みに対処するには政策支援が必要

[[403918]]近年、経済の継続的な発展に伴い、わが国では中間所得層の総数が増加しています。現在...

映画での演技から運転まで、人工知能の実装の5つの主要な方向性は次のとおりです。

この記事は公開アカウント「Reading Core Technique」(ID: AI_Discov...

レノボAmu:シーンインテリジェンスの時代に新たな「三大デバイス」を再定義

3月19日、杭州でCSHIA 2019スマートホーム業界開幕式が開催されました。ブランドメーカー、イ...

エンタープライズ チャットボットは超パーソナライズされたエクスペリエンスを提供できますか?

エンタープライズ チャットボットは脳死状態です。彼らには認知力も深みもなく、リアルタイムの概念や状況...

マスク氏は人気検索に頻繁に登場、テスラは「過大評価されている」

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

...