【C++学習|豆知識】C++開発の必須知識:std::make_sharedでメモリ管理をスマートに

1. 導入

C++で動的にメモリを確保する際、手動でdeleteを行うとメモリリークの危険が伴います。そこで登場するのがスマートポインタですが、単にstd::shared_ptrをnewで生成するだけでは不十分な場合があります。本記事では、メモリ効率と安全性、そしてコードの簡潔さを両立させるstd::make_sharedの重要性について解説します。

2. 基礎知識

std::shared_ptrは、参照カウンタを用いて、オブジェクトを指す所有者がいなくなった瞬間に自動的にメモリを解放するスマートポインタです。
通常、std::shared_ptr ptr(new T())のように生成すると、1. Tのメモリ確保、2. 制御ブロック(参照カウンタなどを管理する領域)のメモリ確保、という2回のメモリ確保が発生します。std::make_sharedはこれらを1回のメモリ確保に統合するため、パフォーマンスとメモリの断片化防止の面で非常に優れています。

3. 実装/解決策

std::make_sharedを使用することで、new演算子を直接記述する必要がなくなります。これにより、例外安全性が向上します。例えば、関数の引数として複数のnewが渡される場合、ある箇所で例外が発生するとメモリリークが起きるリスクがありますが、make_sharedを使えばその懸念を解消できます。

4. サンプルプログラム

以下は、std::make_sharedを使用してクラスを生成する実用的なコードです。

#include
include
include

class User {
public:
User(std::string name) : name_(name) {
std::cout << name_ << " が作成されました。" << std::endl; } ~User() { std::cout << name_ << " が破棄されました。" << std::endl; } void SayHello() { std::cout << "こんにちは、" << name_ << "です。" << std::endl; } private: std::string name_; }; int main() { // std::make_sharedを使用してオブジェクトを生成 // コンストラクタの引数はmake_sharedの引数として渡します auto user = std::make_shared("エンジニア");

user->SayHello();

// 参照が切れると自動的にメモリが解放されます
return 0;
}

5. 応用・注意点

std::make_sharedには1点だけ注意すべきケースがあります。それは、オブジェクトのサイズが非常に大きく、かつstd::weak_ptrによって参照が保持され続ける期間が長い場合です。
std::make_sharedは「オブジェクト」と「制御ブロック」を一つのメモリ領域に確保するため、オブジェクトへの参照がなくなっても、weak_ptrが残っている限りメモリ全体が解放されません。この特殊なケース以外では、基本的にstd::make_sharedを積極的に使用するのが現代のC++開発におけるベストプラクティスです。

コメント

タイトルとURLをコピーしました