コンテンツにスキップ

C++/標準ライブラリ/メモリ管理ライブラリ

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

この節では、メモリ管理コンポーネントについて説明します。 以下のサブセクションでは、一般メモリ管理機能、スマートポインタ、メモリリソース、スコープアロケータについて説明します。

ヘッダー一覧

[編集]

この章で扱うヘッダーファイルは以下の通りです。

メモリ
<cstdlib>, <memory>
スマートポインタ
<memory>
メモリリソース
<memory_resource>
スコープアロケータ
<scoped_allocator>

20.2 メモリ

[編集]

20.2.1 一般

[編集]

この節では、ヘッダファイル <memory><cstdlib> の一部の内容について説明します。

20.2.2 ヘッダ <memory> 概要

[編集]

<memory> ヘッダではいくつかの型とファンクションテンプレートを定義しています。これらは、ポインタやポインタのような型のプロパティを記述し、コンテナやその他のテンプレート型のメモリ管理、オブジェクトの破棄、未初期化メモリバッファ上でのオブジェクト構築を行います (20.2.3 - 20.2.11、27.11)。このヘッダでは、テンプレート unique_ptrshared_ptrweak_ptrout_ptr_tinout_ptr_t と、これらの型のオブジェクトで動作するさまざまなファンクションテンプレートも定義しています (20.3)。

POINTER_OF(T)

[編集]

POINTER_OF(T) は以下の型を表します:

  • T::pointer が有効で型を表す場合はその型
  • そうでない場合で T::element_type が有効で型を表す場合は T::element_type*
  • それ以外の場合は pointer_traits<T>::element_type*

POINTER_OF_OR(T, U)

[編集]

POINTER_OF_OR(T, U) は以下の型を表します:

  • POINTER_OF(T) が有効で型を表す場合はその型
  • そうでない場合は U

以下に <memory> ヘッダの主な内容を示します:

namespace std {
  // ポインタ特性
  template<class Ptr> struct pointer_traits;
  template<class T> struct pointer_traits<T*>;

  // ポインタ変換
  template<class T> constexpr T* to_address(T* p) noexcept;
  template<class Ptr> constexpr auto to_address(const Ptr& p) noexcept;

  // ポインタアライメント
  void* align(size_t alignment, size_t size, void*& ptr, size_t& space);
  template<size_t N, class T> [[nodiscard]] constexpr T* assume_aligned(T* ptr);
  
  // 明示的ライフタイム管理
  template<class T> T* start_lifetime_as(void* p) noexcept;
  ...

  // アロケータ引数タグ 
  struct allocator_arg_t;
  inline constexpr allocator_arg_t allocator_arg{};

  // uses_allocator
  template<class T, class Alloc> struct uses_allocator;
  template<class T, class Alloc> constexpr bool uses_allocator_v;
  template<class T, class Alloc, class...Args> 
    constexpr auto uses_allocator_construction_args(const Alloc& alloc, Args&&... args) noexcept;
  ...

  // アロケータ特性
  template<class Alloc> struct allocator_traits;
  
  // デフォルトアロケータ
  template<class T> class allocator;
  
  // addressof
  template<class T> constexpr T* addressof(T& r) noexcept;

  // 特殊アルゴリズム 
  template<class T> T* uninitialized_default_construct(...);
  ...
}

この節では、メモリ管理に関連した型とユーティリティ関数について説明しています。ポインタ特性、アロケータ特性、デフォルトアロケータ、明示的なライフタイム管理、uses_allocatorコンストラクタ補助ユーティリティなどが含まれます。

20.2.3 ポインタ特性

[編集]

pointer_traitsクラステンプレートは、さまざまなポインタ型に対して統一されたインターフェースを提供します。

template<class Ptr> struct pointer_traits {
  // メンバ型エイリアス
  using pointer = Ptr; 
  using element_type = /* ... */;
  using difference_type = /* ... */;
  template<class U> using rebind = /* ... */;
   
  // メンバ関数
  static constexpr pointer pointer_to(/* ... */ r) noexcept;
};

template<class T> struct pointer_traits<T*> {
  using pointer = T*;
  using element_type = T;
  using difference_type = ptrdiff_t;
  template<class U> using rebind = U*;
  
  static constexpr pointer pointer_to(/* ... */ r) noexcept;
};

pointer_traitsは、ポインタ型に関する情報(要素型、差分型など)とユーティリティ関数(pointer_to)を提供します。

20.2.4 ポインタ変換

[編集]

to_address関数は、ポインタや参照からアドレスを取得します。

template<class T> constexpr T* to_address(T* p) noexcept;
template<class Ptr> constexpr auto to_address(const Ptr& p) noexcept;

20.2.5 ポインタアライメント

[編集]

この節では、アライメント調整のためのユーティリティ関数が提供されています。

  • alignは指定されたアライメントとサイズに合わせてメモリ領域を確保します
  • assume_alignedは与えられたポインタがアライメントされていることを示します

20.2.6 明示的ライフタイム管理

[編集]

この節では、オブジェクトのライフタイム管理のための関数が定義されています。

  • start_lifetime_asはメモリ領域上に指定された型のオブジェクトを配置します
  • start_lifetime_as_arrayは配列のオブジェクトを配置します

20.2.7 アロケータ引数タグ

[編集]

allocator_arg_t構造体は、アロケータを引数に取るコンストラクタの曖昧性解消に使用されます。

struct allocator_arg_t { };
inline constexpr allocator_arg_t allocator_arg{};

20.2.8 uses_allocator

[編集]

uses_allocatorトレイトは、型がアロケータを使用するかどうかを検出します。uses_allocator_construction_argsユーティリティは、アロケータを適切に渡すための引数を生成します。

 
template<class T, class Alloc> struct uses_allocator;
template<class T, class Alloc> constexpr bool uses_allocator_v;
template<class T, class Alloc, class...Args>
  constexpr auto uses_allocator_construction_args(const Alloc& alloc, Args&&...);

20.2.9 アロケータ特性

[編集]

allocator_traitsクラステンプレートは、すべてのアロケータ型に対して統一されたインターフェースを提供します。

template<class Alloc> struct allocator_traits {
  // メンバ型エイリアス
  using allocator_type = Alloc;
  using value_type = /* ... */;
  using pointer = /* ... */;
  // ...
   
  // メンバ関数 
  static constexpr pointer allocate(Alloc& a, size_type n);
  static constexpr void deallocate(Alloc& a, pointer p, size_type n);
  // ...
};

アロケータ特性は、メモリ割り当て/解放、オブジェクトの構築/破棄などのインターフェースを提供します。

20.2.10 デフォルトアロケータ

[編集]

標準ライブラリは、デフォルトのアロケータクラス allocator を提供しています。

template<class T> class allocator {
public:
  using value_type = T;
  using size_type = size_t;
  using difference_type = ptrdiff_t;
  using propagate_on_container_move_assignment = true_type;

  constexpr allocator() noexcept;
  constexpr allocator(const allocator&) noexcept;
  template<class U> constexpr allocator(const allocator<U>&) noexcept;
  constexpr ~allocator();

  constexpr allocator& operator=(const allocator&) = default;

  [[nodiscard]] constexpr T* allocate(size_t n);
  [[nodiscard]] constexpr allocation_result<T*> allocate_at_least(size_t n);
  constexpr void deallocate(T* p, size_t n);
};

allocatorは、値型Tのオブジェクトを動的に確保・解放するためのメンバ関数を提供します。

  • allocateはメモリを動的に確保し、確保された領域の先頭ポインタを返します
  • allocate_at_leastは要求されたサイズ以上の領域を確保し、その先頭ポインタとサイズを返します
  • deallocateは以前に確保されたメモリを解放します

デフォルトのアロケータは、::operator new::operator deleteを使用してメモリ管理を行います。

20.2.11 addressof

[編集]

addressof関数は、オブジェクトやメンバ関数へのポインタを取得します。オーバロードされたoperator&があっても、実際のオブジェクトのアドレスを返します。

template<class T> constexpr T* addressof(T& r) noexcept;

20.2.12 Cライブラリメモリ割り当て

[編集]

この節では、Cライブラリのメモリ割り当て関数についても言及されています。<cstdlib>ヘッダで定義されるmalloccallocreallocfree関数が含まれます。

これらの関数は、C標準に準拠したメモリ管理を行います。::operator new/deleteとは別の実装で、オブジェクトの明示的な生成や破棄は行いません。

20.3 スマートポインタ

[編集]

この節では、スマートポインタの実装について説明されています。

20.3.1 unique_ptr

[編集]

unique_ptrは、単一のオブジェクトを所有するスマートポインタです。ムーブ可能で、コピー不可能なユニークな所有権を持ちます。

template<class T, class D = default_delete<T>> class unique_ptr;

// 生成ヘルパー
template<class T, class... Args>
unique_ptr<T> make_unique(Args&&... args);

template<class T>
unique_ptr<T> make_unique_for_overwrite();

// ユーティリティ
template<class T, class D>
void swap(unique_ptr<T, D>& x, unique_ptr<T, D>& y);

// 比較演算子
template<class T1, class D1, class T2, class D2>
bool operator==(const unique_ptr<T1, D1>& x, const unique_ptr<T2, D2>& y);

unique_ptrはオブジェクトの排他的な所有権を持ち、オブジェクトのライフタイムを自動的に管理します。

20.3.2 shared_ptr

[編集]

shared_ptrは、複数の共有所有者が存在する場合に使用されるスマートポインタです。オブジェクトの共有所有権をカウントします。

template<class T> class shared_ptr;

// 生成ヘルパー  
template<class T, class... Args>
shared_ptr<T> make_shared(Args&&... args);

// ユーティリティ
template<class T>
void swap(shared_ptr<T>& a, shared_ptr<T>& b);

// 比較演算子
template<class T, class U>
bool operator==(const shared_ptr<T>& a, const shared_ptr<U>& b);

// キャスト
template<class T, class U>
shared_ptr<T> static_pointer_cast(const shared_ptr<U>& r);

shared_ptrは、参照カウンタによりオブジェクトの共有所有権を管理します。最後のshared_ptrが破棄されると、オブジェクトが自動的に削除されます。

20.3.2.3 weak_ptr

[編集]

weak_ptrは、shared_ptrと関連付けられたスマートポインタで、オブジェクトの所有権を持ちません。オブジェクトが存在するかどうかを確認したり、一時的にshared_ptrを取得したりするために使用されます。

template<class T> class weak_ptr;

weak_ptrshared_ptrの一時的なビューを提供します。

20.3.4 out_ptr_t、inout_ptr_t

[編集]

out_ptr_tinout_ptr_tは、関数呼び出しで使用されるスマートポインタのラッパークラスです。これらは、スマートポインタの引数を明示的に渡す際の曖昧さを解決するのに役立ちます。

template<class Smart, class Pointer, class... Args>
class out_ptr_t;

template<class Smart, class Pointer, class... Args>  
class inout_ptr_t;

関数テンプレート out_ptrinout_ptrは、これらのラッパークラスのオブジェクトを生成するのに使用されます。

これらのクラスは、関数呼び出しでスマートポインタを明示的に渡す際の曖昧さを解決するのに役立ちます。

以上が「メモリ」の20.3節におけるスマートポインタに関する主な内容になります。unique_ptrshared_ptrweak_ptr、およびそれらに関連するユーティリティクラスについて解説しました。

メモリリソース

[編集]

スコープアロケータ

[編集]