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

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

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

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

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

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

ブログ    

推薦する

データサイエンスと機械学習のためのトップ 16 プラットフォーム

調査会社ガートナーは、データ サイエンスおよび機械学習プラットフォームを「さまざまなデータ サイエン...

多様な用途に焦点を当て、ドローンマッピングはますます熱を帯びている

農作物の保護から電力検査、映画やテレビの撮影から消防救助、緊急通信から交通検査まで、ドローンの活用が...

人と「人」の対立を実感する: よく使われるAIセキュリティツールのインベントリ

今日、サイバー犯罪者は機械学習や人工知能などの新しいテクノロジーを使用して、標的の行動をより深く理解...

製品の価格については心配しないでください。AI が教えてくれます!

[[341780]] ▲写真:ゲッティベインが 1,700 人以上のビジネス リーダーを対象に実施...

...

2020年以降のAIとデータのトレンド

2019 年は、データ、分析、機械学習、人工知能の市場において継続的な発展が見られた年でした。 Sa...

...

AIを使用してC++、Java、Pythonコードを翻訳し、最大成功率は80.9%です。

この記事はAI新メディアQuantum Bit(公開アカウントID:QbitAI)より許可を得て転載...

最後にもう一度、一貫性のあるハッシュについて長々と話します。

一貫性のあるハッシュについて見てきましたが、一貫性のないハッシュもあるはずです。私たちが普段話題にし...

モデルの解釈可能性に関する詳細な考察: それはどこから来て、どこに向かうのか?

この記事の著者である Cody Marie Wild は、機械学習分野のデータ サイエンティスト (...

アメリカのショッピングプラットフォームStitch Fixの王建強氏:データ主導の意思決定サポートと製品インテリジェンス

[51CTO.comより] 最近、51CTOが主催するWOTAグローバルアーキテクチャと運用技術サミ...

マイクロソフトがML.NETクロスプラットフォーム機械学習フレームワークをオープンソース化し、AIをさらに一歩前進させる

現地時間5月7日、米国シアトルでMicrosoft Buildカンファレンスが開催され、マイクロソフ...

AI 導入の謎を解明: クラウドとエッジ

現在、ディープラーニング テクノロジーを展開できる方法としては、デバイス上への直接展開、クラウド内へ...

...

自己強化型機械学習プロジェクト 10 選

機械学習プロジェクトは大きな発展の可能性を秘めています。最近、韓国の人気ドラマでもこの用語が使用され...