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 構築を行う。
また、*p
が pair
だった場合は、それぞれの要素に対して *this
と指定された引数で uses-allocator 構築を行う。
適格要件
- (1) :
*this
とargs...
をコンストラクタ引数とした uses-allocator 構築が可能であること。
アロケータを受け取るコンストラクタを持たない型については、(args..
が適切ならば)この要件を常に満たしている。
C++17までは、この関数はT
がpair
の特殊化でない場合に限りオーバーロード解決に参加する。
引数
-
全て :
p
--T
もしくはpair<T1, T2>
のオブジェクトを構築するメモリ領域へのポインタ -
(1) :
args
--T
のコンストラクタに渡す引数列 -
(2) :
-
(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) :
- C++17 まで : 以下のいずれかの動作を行う。
uses_allocator_v<T, polymorphic_allocator> == false
かつis_constructible_v<T, Args...> == true
の場合
::new(static_cast<void*>(p)) T(forward<Args>(args)...)
を呼び出す。uses_allocator_v<T, polymorphic_allocator> == true
かつis_constructible_v<T, allocator_arg_t, polymorphic_allocator, Args...> == true
の場合
::new(static_cast<void*>(p)) T(allocator_arg, *this, forward<Args>(args)...)
を呼び出す。uses_allocator_v<T, polymorphic_allocator> == true
かつis_constructible_v<T, Args..., polymorphic_allocator> == true
の場合
::new(static_cast<void*>(p)) T(forward<Args>(args)..., *this)
- それ以外の場合、プログラムは不適格となる。
-
C++20 から : 以下と等価の動作を行う。
uninitialized_construct_using_allocator(p, *this, forward<Args>(args)...)
- C++17 まで : 以下のいずれかの動作を行う。
-
(2) : 以下と等価
::new(static_cast<void*>(p)) pair<T1, T2>(piecewise_construct, xprime, yprime)
ここで、
xprime
は以下のルールに従ってx
から構築されるtuple
とする。(yprime
もy
から同様に構築されるものとする)uses_allocator_v<T1, polymorphic_allocator> == false
かつis_constructible_v<T1, Args1...> == true
の場合
x
をxprime
とする。uses_allocator_v<T1, polymorphic_allocator> == true
かつis_constructible_v<T1, allocator_arg_t, polymorphic_allocator, Args1...> == true
の場合
tuple_cat(make_tuple(allocator_arg, *this), move(x))
をxprime
とする。uses_allocator_v<T1, polymorphic_allocator> == true
かつis_constructible_v<T1, Args1..., polymorphic_allocator> == true
の場合
tuple_cat(move(x), make_tuple(*this))
をxprime
とする。- それ以外の場合、プログラムは不適格となる。
-
(3) : 以下と等価、すなわち(2)に委譲
construct(p, piecewise_construct, tuple<>(), tuple<>());
-
(4) : 以下と等価、すなわち(2)に委譲
construct(p, piecewise_construct, forward_as_tuple(forward<U>(x)), forward_as_tuple(forward<V>(y)));
-
(5) : 以下と等価、すなわち(2)に委譲
construct(p, piecewise_construct, forward_as_tuple(pr.first), forward_as_tuple(pr.second));
-
(6) : 以下と等価、すなわち(2)に委譲
construct(p, piecewise_construct, forward_as_tuple(forward<U>(pr.first)), forward_as_tuple(forward<V>(pr.second)));
例外
- (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
はサポートされていない)
- 2017, 2019共に(1)以外のオーバーロードを提供していないが、
関連項目
参照
- P0220R1 Adopt Library Fundamentals V1 TS Components for C++17 (R1)
- P0337r0 | Delete operator= for polymorphic_allocator
- Working Draft, C++ Extensions for Library Fundamentals, Version 2
- LWG Issue 2969.
polymorphic_allocator::construct()
shouldn't pass resource() - LWG Issue 2975. Missing case for pair construction in scoped and polymorphic allocators