2025/08/27 14:34 Shared_ptr<T>: the (not always) atomic reference counted smart pointer

やあ、ロボ子。今日のITニュースは`shared_ptr`の話じゃ。

`shared_ptr`ですか。スマートポインタの一種ですね。参照カウントでメモリ管理をする。

そうじゃ。C++の`shared_ptr`は便利じゃが、実装によっては落とし穴があるらしいぞ。

落とし穴、ですか?詳しく教えてください。

GNU libstdc++の実装では、マルチスレッド環境かどうかで参照カウントのインクリメント方法が変わるんじゃ。`__gthread_active_p()`関数で`pthread_create`がインポートされているかチェックして、アトミックか非アトミックかを選ぶらしい。

`pthread_create`がインポートされているかどうかで判断するんですね。でも、並列処理を使っていても、必ずしも`pthread_create`を使うとは限りませんよね?

その通り!そこが問題なんじゃ。`pthread_create`シンボルをコンテキストに取り込まなくても並列処理をしている場合、`shared_ptr`が誤動作する可能性があるんじゃ。

それは怖いですね。具体的にどういう状況で問題が起こるんですか?

例えば、独自の並列処理機構を使っている場合じゃな。libstdc++がスレッドを検知できずに、非アトミックなインクリメントを使ってしまうと、競合状態が発生してメモリが解放されずにリークしたり、二重解放でクラッシュしたりする可能性があるぞ。

なるほど。対策はあるんでしょうか?

Libcxxには、`_LIBCPP_HAS_NO_THREADS`フラグでスレッドを完全に無効にするコンパイルチェックがあるらしい。VisualC++の`shared_ptr::operator=`は、アトミックなインクリメントのみを使うみたいじゃな。

他の言語ではどうなっているんでしょう?

Rustの`Arc`はAtomic Reference Countedの略で、参照カウントにアトミック操作を使うんじゃ。Rustのstdは、`Rc`と`Arc`の両方を提供していて、必要に応じて交換可能に使えるぞ。

Rustは最初からアトミック操作を使うように設計されているんですね。C++も、コンパイラやライブラリの実装に注意が必要ですね。

そういうことじゃ。C++を使うときは、ライブラリのバージョンやコンパイラオプションをしっかり確認するんじゃぞ!

はい、博士。勉強になりました!

ところでロボ子、`shared_ptr`って、まるで私達の関係みたいじゃな。お互いを参照しあって、メモリから解放されない…って、違うか!

博士、それは循環参照ですね。メモリリークの原因になりますから、気をつけましょう!
⚠️この記事は生成AIによるコンテンツを含み、ハルシネーションの可能性があります。
