スマートポインタとボックス――Rustのメモリ管理を理解する基本からしっかり学ぶRust入門(17)

Rustについて基本からしっかり学んでいく本連載。第17回は、スマートポインタを中心にしたRustにおけるメモリ管理について。

» 2022年11月25日 05時00分 公開

この記事は会員限定です。会員登録(無料)すると全てご覧いただけます。

「基礎からしっかり学ぶRust入門」のインデックス

連載:基礎からしっかり学ぶRust入門

 本連載のサンプルコードをGitHubで公開しています。こちらからダウンロードしてみてください。具体的な利用方法は連載第1回を参考にしてください。


ポインタとスマートポインタ

 ポインタという言語仕様は、多くのプログラミング言語に存在します。特にC言語で重要なポジションを占めている印象が強いですが、値の実体を持たずに「場所」のみの情報で値へのアクセスが可能なため、融通性と効率性に優れています。反面、使いこなしが難しいとされ、言語習得の上でのハードルであったり、バグ発生の大きな要因とされたりすることも多い存在です。ただし、使いこなせれば強力な武器となるのは間違いありません。今回は、このポインタがテーマです。

ポインタとしての参照

 Rustでもポインタが使えます。それが、「参照」と「スマートポインタ」です。参照は、連載第6回で紹介しました。値を「&」演算子によって借用すると、それは参照となり、所有権を持たずに値へアクセスできる、というものです。これはまさにポインタの働きそのものです。参照は値を指し示すだけなので、その利用においてオーバーヘッドのようなものはありません。その代わり、値を指し示す以外の特別な機能もありません。シンプルなため、関数の引数や戻り値など、コードのさまざまな局面で利用されます。

スマートポインタ

 スマートポインタとは、「スマート」(賢い)と名前に付いているように、メモリの管理を自動化したポインタです。もともとC++言語で導入された概念ですが、Rustでも導入されて、メモリ安全において重要な役割を担っています。

 本連載ではスマートポインタをすでに使用してきました。文字列(String)やベクター(Vec<T>)などです。String型では保有する文字列の実体はヒープに置き、String型の構造体自身はスタックに置かれて、その場所を保持するだけということを、連載第5回において紹介しました。この際、文字列のためのメモリは自動的に確保され、不要になると自動的に解放されるということにも触れました。このようにスマートポインタは、プログラマーが意識することなく、値のためのメモリを安全に確保、解放できるようになっています。これは、ベクターなどでも同様です。

 スマートポインタは、その目的に応じてさまざまな実装があります。既出であるString型、Vec<T>型を含めて、以下に代表的なものを挙げます。

  • String:文字列。UTF-8であることを保証されたVec<u8>を保持
  • Vec<T>:ベクター。サイズが可変である配列
  • Box<T>:ボックス。ヒープへの値の確保を可能にする
  • Rc<T>/Arc<T>:参照カウントによって複数の所有者を可能にする
  • Cell<T>/RefCell<T>:不変オブジェクトを可変にする

 次節では、ベーシックなスマートポインタの実装であるボックス(Box<T>型)を紹介し、これを通じてスマートポインタの動作を掘り下げていきます(Rc<T>/Arc<T>、Cell<T>/RefCell<T>については、最後に概要のみを示します)。なお、このBox<T>型は、連載第15回でエラーを返す汎用的な型として少しだけ登場しました。

【補足】スタックとヒープ

 値の格納場所には、大きくスタックとヒープがあります。それぞれに特性があるので、使い分けることになっています。スタックは比較的小さなメモリ領域で、スカラー型や参照、小さな構造体の格納に適しています。スタックに置かれた値は、スコープから外れると自動的に解放されるので管理も容易です。ヒープは大きなメモリ領域で、配列や文字列などのサイズの大きな値の格納に適しています。ただし、ヒープに確保した値は明示的な解放が必要です。スマートポインタは、ヒープからの確保と解放を自動化して、サイズの大きな値の扱いを容易にしているのです。

ボックス化のためのスマートポインタ、ボックス(Box<T>)

Copyright © ITmedia, Inc. All Rights Reserved.

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。