C++言語

shared_ptrでカスタムデリータを指定する方法

2023年5月1日

shared_ptr<T> は、メモリを自動的に解放してくれるスマートポインタの一種で、
カスタムデリータを設定できるようになっています。

本記事では、カスタムデリータ(Custom Deleter)を指定する方法をご紹介します。

参考スマートポインタとは?C++での使用方法とメリット

C++ではポインタを使ってメモリの内容を書き換えたり、同じメモリを参照したりします。しかし、メモリリークや解放済みのメモリにアクセス、メモリの2重解放、などの問題に悩まされます。本記事では、これらの悩みを解決するスマートポインタについて紹介します。

続きを見る

参考

shared_ptr<T> については「スマートポインタとは?」で詳しく解説しています。
C++11 で実装された機能で、メモリリークや2重解放を回避する手法として利用されています。

 

カスタムデリータとは?

shared_ptr<T> が所有するポインタへの参照がゼロになったタイミングで自動的に解放されます。
解放の際に呼び出されるデフォルトのデリータは、delete となっています。

例えば、以下のような場合、delete を呼び出すだけでは正しい終了処理となりません。

SANACHAN
SANACHAN
fclose() を呼び出してほしいところですね。

このような場合に、カスタムデリータを指定することで解決することができます。
その名の通り、解放の際に実行されるデリータに、独自の処理を指定することができます。

 

カスタムデリータを指定する方法

deleter 関数を使用

既存の関数や独自に実装した関数を deleter として指定することができます。
先ほどの fopen の場合は、以下のように記述することで fclose が呼び出されます。

SANACHAN
SANACHAN
引数のない deleter を指定した場合は、shared_ptr<T> に指定した
typename の生ポインタが渡されます。

 

独自に記述した deleter を指定する場合は、以下のように記述します。

 

ラムダ式を使用

shared_ptr<T> と同じくして C++11 で導入された Lambda 式(ラムダ式)で指定することもできます。

 

カスタムデリータの利用例

先ほどの fopen / fclose も一例ですが、他にも便利に利用できるケースがあります。
ここでは、別プロセスを起動する popen / pclose の例を紹介します。

SANACHAN
SANACHAN
コマンドを popen で起動し、標準出力に出力される文字列を表示します。

 

起動したプロセスの終了ステータスを取得したい場合は、ラムダ式を利用して以下のように記述します。

SANACHAN
SANACHAN
std::string は mutable なため、こそっと改良しています(笑)

 

カスタムデリータの注意点

shared_ptr<T> でカスタムデリータを指定する場合、注意すべきことがあります。

  • make_shared を使用できない
    カスタムデリータは、shared_ptr<T>のコンストラクタにのみ指定できます。
    そのため、make_sharedを利用することはできなくなります。
  • 同じオブジェクトに指定できるカスタムデリータは1つ
    カスタムデリータを指定したshared_ptr<T>をさらにshared_ptr<T>で参照する場合、
    2つ目のスマートポインタへは、カスタムデリータを指定することができません。
    1つのオブジェクトに対して、1つのみデリータを指定することができます。

 

おわりに

いかがでしたでしょうか。
今回は、shared_ptr<T> にカスタムデリータを指定する方法を紹介しました。

C言語で書いた場合と比較して、エラー処理が書きやすくなると感じていただけましたでしょうか?
C++を使用する場合は、言語仕様を活用することで、効率よい設計・実装を行えます。

参考になりましたらうれしいです。

 

こちらの記事もよく読まれています

  • この記事を書いた人
  • 最新記事
SANACHAN

SANACHAN

「生涯一エンジニア」を掲げ、大手グローバル企業でSE/PGとして8年勤め、キャリアアップ転職した現役のエンジニアです。世にあるメジャーな全プログラム言語(コボル除く)を自由に扱えます。一児の父。自分のため、家族のため、日々勉強してます。システムエンジニア、プログラミングに関する情報を蓄積している雑記帳です。

-C++言語
-, ,