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

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

[[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ブラックテクノロジー:暗闇でも正確に顔を認識できる。これに不安を感じる人はいるだろうか?

[[227002]]今日お話しするのは、「そんな手術があるの?」と第一印象でとても驚く内容ですが、...

機械学習による物流とサプライチェーン管理の変革

機械学習は、リアルタイムの需要予測、持続可能な物流、高度な予測分析など、大きなメリットをもたらします...

教育ロボットとベテラン教師の戦い:学習の効率を高めるのはどちらでしょうか?

[51CTO.com]地理的制約と教師の制約により、中国では質の高い教育資源が常に極めて不足してい...

人工知能技術が都市交通のインテリジェント化を加速

特に交通分野において、2021年は人工知能の発展が最も速く、需要が最も高まる年です。都市交通における...

...

インダストリー 5.0: スマート シティの未来を形作るテクノロジーのメガトレンドの融合

この新しいフェーズは、ディープ テクノロジーの開発と採用のかつてない増加、世界の人口動態の大きな変化...

GitHub のスター数が 16.9k に急上昇、MetaGPT はインターネット全体で人気に!

著者 | 王 睿平今日、大規模言語モデル技術が継続的に成熟するにつれ、専門家はそれを活用してインテリ...

...

2020年のディープラーニング開発のレビュー

近年の傾向に倣い、ディープラーニングは 2020 年も最も急速に成長している分野の 1 つであり続け...

Googleの最新の「効率的なトランスフォーマー」では、トランスフォーマーの効率を向上させる方法を説明しています

トランスフォーマー モデルは現在、言語、視覚、強化学習などの分野での有効性から注目を集めています。た...

ジェネレーティブ AI: 職場の CIO にとって未知の要素

組織のエンドユーザーとますますインテリジェントになるソフトウェア ツールとの間の生産的なパートナーシ...

人事戦略と人材開発の形成における AI の役割

AI の力を活用することで、人事チームは複雑な課題に対処し、効率性を向上させ、前向きな職場環境を育む...

グラフィカル分散コンセンサスアルゴリズム

本日の記事では、グラフを使用して分散一貫性の実装原則を深く研究し、理解します。まず、自己を見つめ直す...

AIチップアーキテクチャは最先端へ向かう

企業は、AI をエッジに押し上げるための最適な武器として、さまざまなチップ アーキテクチャを採用しよ...

青春が戻ってきた! AIが『スラムダンク』の登場人物を実在の人物に変身させたら、一番イケメンは流川楓じゃないのか?

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