最終更新日時(UTC):
が更新

履歴 編集

function
<memory_resource>

std::pmr::polymorphic_allocator::construct(C++17)

template <class T, class... Args>
void construct(T* p, Args&&... args);                   //(1)

template <class T1, class T2, class... Args1, class... Args2>
void construct(pair<T1, T2>* p, piecewise_construct_t,
               tuple<Args1...> x, tuple<Args2...> y);   //(2) C++17 まで

template <class T1, class T2>
void construct(pair<T1, T2>* p);                        //(3) C++17 まで

template <class T1, class T2, class U, class V>
void construct(pair<T1, T2>* p, U&& x, V&& y);          //(4) C++17 まで

template <class T1, class T2, class U, class V>
void construct(pair<T1, T2>* p, const pair<U, V>& pr);  //(5) C++17 まで

template <class T1, class T2, class U, class V>
void construct(pair<T1, T2>* p, pair<U, V>&& pr);       //(6) C++17 まで

概要

p で指定された領域に、*this と指定された引数で uses-allocator 構築を行う。
また、*ppair だった場合は、それぞれの要素に対して *this と指定された引数で uses-allocator 構築を行う。

適格要件

  • (1) : *thisargs... をコンストラクタ引数とした uses-allocator 構築が可能であること。
    アロケータを受け取るコンストラクタを持たない型については、(args.. が適切ならば)この要件を常に満たしている。
    C++17までは、この関数は Tpair の特殊化でない場合に限りオーバーロード解決に参加する。

引数

  • 全て : p -- T もしくは pair<T1, T2> のオブジェクトを構築するメモリ領域へのポインタ

  • (1) : args -- T のコンストラクタに渡す引数列

  • (2) :

    • x -- T1 のコンストラクタに渡す引数を持つ tuple オブジェクト
    • y -- T2 のコンストラクタに渡す引数を持つ tuple オブジェクト
  • (4) :

    • x -- T1 のコンストラクタに渡す引数
    • y -- T2 のコンストラクタに渡す引数
  • (5) : pr -- T1, T2 のコンストラクタにそれぞれコピーして渡す引数 U, V のオブジェクトを持つ pair<U, V>オブジェクト

  • (6) : pr -- T1, T2 のコンストラクタにそれぞれ forward して渡す引数 U, V のオブジェクトを持つ pair<U, V> オブジェクト

効果

例外

  • (1) : Tのコンストラクタが例外を投げないならば、この関数も例外を投げない。

備考

  • C++20 における変更は、一見新規導入されたユーティリティ関数(uninitialized_construct_using_allocator)を使用して定義を簡略化しただけのように思えるが、実はこの変更によりネストした pair に対しても uses-allocator 構築がサポートされるように改善されている。

(1)の例

#include <iostream>
#include <memory_resource>

int main()
{
  std::pmr::polymorphic_allocator<int> alloc{};

  //メモリの確保
  int* array = alloc.allocate(4);

  //要素を構築
  for (int i = 0; i < 4; ++i) {
    alloc.construct(array + i, i);
  }

  for (int i = 0; i < 4; ++i) {
    std::cout << array[i] << std::endl;
  }

  //要素を破棄
  for (int i = 0; i < 4; ++i) {
    alloc.destroy(array + i);
  }

  //メモリの解放
  alloc.deallocate(array, 4);
}

出力

0
1
2
3

pair関連のオーバーロードの例

#include <iostream>
#include <memory_resource>
#include <string>
#include <tuple>
#include <utility>

int main()
{
  //intとpolymorphic_allocatorを用いるstringのpair
  using pair = std::pair<int, std::pmr::string>;

  //memory_resourceとしてmonotonic_buffer_resourceを使用
  auto mr = std::pmr::monotonic_buffer_resource{};
  std::pmr::polymorphic_allocator<pair> alloc{&mr};

  std::cout << std::boolalpha;
  std::cout << "(2)" << std::endl;

  //(2)
  {
    pair* p = alloc.allocate(1);

    alloc.construct(p, std::piecewise_construct
        , std::make_tuple(128)         //intを128で初期化
        , std::make_tuple("string", 3) //string("string", 3)で初期化(最初の3文字を保持する)
    );

    std::cout << p->first << std::endl;
    std::cout << p->second << std::endl;
    //アロケータが伝搬している
    std::cout << (p->second.get_allocator() == alloc) << std::endl;
  }

  std::cout << "\n(3)" << std::endl;

  //(3)
  {
    pair* p = alloc.allocate(1);

    alloc.construct(p);  //両要素をデフォルト構築

    std::cout << p->first << std::endl;
    std::cout << p->second << std::endl;
    //アロケータが伝搬している
    std::cout << (p->second.get_allocator() == alloc) << std::endl;
  }

  std::cout << "\n(4)" << std::endl;

  //(4)
  {
    pair* p = alloc.allocate(1);

    alloc.construct(p, 128, "string");  //両要素をこれらの値からムーブ構築

    std::cout << p->first << std::endl;
    std::cout << p->second << std::endl;
    //アロケータが伝搬している
    std::cout << (p->second.get_allocator() == alloc) << std::endl;
  }

  std::cout << "\n(5)" << std::endl;

  //(5)
  {
    pair* p = alloc.allocate(1);

    const auto v = std::make_pair(128, "copy");
    alloc.construct(p, v);  //両要素を変換可能なpairからコピー構築

    std::cout << p->first << std::endl;
    std::cout << p->second << std::endl;
    //アロケータが伝搬している
    std::cout << (p->second.get_allocator() == alloc) << std::endl;
  }

  std::cout << "\n(6)" << std::endl;

  //(6)
  {
    pair* p = alloc.allocate(1);

    alloc.construct(p, std::make_pair(128, "move"));  //両要素を変換可能なpairからムーブ構築

    std::cout << p->first << std::endl;
    std::cout << p->second << std::endl;
    //アロケータが伝搬している
    std::cout << (p->second.get_allocator() == alloc) << std::endl;
  }
}

出力

(2)
128
str
true

(3)
0

true

(4)
128
string
true

(5)
128
copy
true

(6)
128
move
true

ネストした pair の例

#include <iostream>
#include <string>
#include <utility>
#include <memory_resource>

int main()
{
  using pair = std::pair<std::pair<int, std::pmr::string>, std::pmr::string>;

  auto mr = std::pmr::monotonic_buffer_resource{};
  std::pmr::polymorphic_allocator<pair> alloc{&mr};

  std::cout << std::boolalpha;

  pair* p = alloc.allocate(1);

  alloc.construct(p);

  std::cout << (p->first.second.get_allocator() == alloc) << '\n';
  std::cout << (p->second.get_allocator() == alloc) << '\n';

  alloc.destroy(p);

  alloc.deallocate(p, 1);
}

C++17 における出力

false
true

C++20 における出力

true
true

バージョン

言語

  • C++17

処理系

  • Clang: ??
  • GCC: 9.1
  • Visual C++: 2017 update 6
    • 2017, 2019共に(1)以外のオーバーロードを提供していないが、pair の各要素に対する uses-allocator 構築をサポートしている。(ただし、C++20 モードでもネストした pair はサポートされていない)

関連項目

参照