コンテンツにスキップ

C++/スマートポインタ

出典: フリー教科書『ウィキブックス(Wikibooks)』
< C++

スマートポインタとは

[編集]

ポインタは C++ でメモリ管理を行う上で非常に重要な役割を果たしますが、その使い方を誤ると、メモリリークやダングリングポインタなどの深刻な問題を引き起こす可能性があります。このような問題を回避するために、スマートポインタが導入されました。

スマートポインタは、メモリ領域の自動的な割り当てと解放を行うクラステンプレートで、C++23では特にコルーチンやモジュールとの連携が強化されています。

// C++20: designated initializersとスマートポインタ
struct Config {
    int value;
    std::string name;
};

auto config = std::make_unique<Config>(Config{
    .value = 42,
    .name = "test"
});

std::unique_ptr

[編集]

std::unique_ptrは、所有権ベースのメモリ管理を行うスマートポインタです。C++20以降、コンストレイントと組み合わせることで、より型安全な使用が可能になりました。

// C++20: コンセプトを使用した制約付きスマートポインタ
template<typename T>
    requires std::is_base_of_v<Base, T>
auto create_derived() -> std::unique_ptr<Base> {
    return std::make_unique<T>();
}

// C++23: deducing thisとの組み合わせ
class Widget {
    template<typename Self>
    auto use(this Self&& self) {
        return std::make_unique<std::remove_reference_t<Self>>(
            std::forward<Self>(self));
    }
};

std::shared_ptr

[編集]

C++20以降、std::shared_ptrはアトミック操作の最適化が行われ、パフォーマンスが向上しています。また、std::atomic<std::shared_ptr>のロックフリー実装が保証されるようになりました。

// C++20: アトミック操作の例
std::shared_ptr<int> sp = std::make_shared<int>(42);
std::atomic<std::shared_ptr<int>> asp{sp};

// ロックフリーな更新
asp.store(std::make_shared<int>(100));

// C++23: 参照カウントの最適化
struct Node {
    std::shared_ptr<Node> next;
    std::weak_ptr<Node> prev;  // 循環参照を防ぐ
};

スマートポインタと新しいメモリ管理

[編集]

C++23では、メモリ管理に関する新しい機能が追加されています:

// C++23: std::stacktraceとの連携
void process_resource() {
    auto ptr = std::make_unique<Resource>();
    try {
        ptr->use();
    } catch (const std::exception& e) {
        std::cout << "Exception at: " << std::stacktrace::current() << '\n';
        throw;
    }
}

// メモリリソースの管理
std::pmr::synchronized_pool_resource pool;
std::pmr::polymorphic_allocator<int> alloc{&pool};
auto ptr = std::unique_ptr<int, std::pmr::polymorphic_allocator<int>>(
    alloc.allocate(1), 
    [&](int* p) { alloc.deallocate(p, 1); }
);

スマートポインタとモジュール

[編集]

C++20のモジュールシステムでは、スマートポインタの使用方法が変わります:

// mymodule.ixx
export module mymodule;
export namespace mylib {
    template<typename T>
    using Ptr = std::unique_ptr<T>;
    
    export template<typename T>
    auto create() -> Ptr<T> {
        return std::make_unique<T>();
    }
}

ベストプラクティス(2024年更新)

[編集]
コルーチンとの統合
C++20以降のコルーチンでは、スマートポインタを使用したリソース管理が重要です。
モジュール化
C++20のモジュールシステムでは、スマートポインタのエクスポートと使用に注意が必要です。
constexpr対応
C++20以降、多くのスマートポインタ操作がconstexpr対応になっています。
スレッド安全性
C++23では、アトミック操作の最適化により、マルチスレッド環境でのパフォーマンスが向上しています。
C++23のメモリ管理の進化
C++23では、以下の機能が追加されました:
  • スタックトレースのサポート
  • PMRアロケータとの統合強化
  • アトミック操作の最適化
  • デバッグ支援機能の強化
これらの機能により、メモリリークの検出や性能分析が容易になっています。

まとめ

[編集]

C++23までの進化により、スマートポインタはより安全で効率的に利用できるようになりました。特に:

  • モジュールシステムとの統合
  • コルーチンサポート
  • パフォーマンスの最適化
  • デバッグ機能の強化

これらの機能を適切に活用することで、より堅牢なメモリ管理が実現できます。