The following code:
std::pmr::vector<std::pmr::vector<int>> outer_vec(std::pmr::get_default_resource());
outer_vec.emplace_back(std::pmr::get_default_resource());
fails with quite inconceivable error message ending with
static assertion failed: construction with an allocator must be possible if uses_allocator is true
The vector can clearly be constructed with an argument of std::pmr::get_default_resource()
, such as:
std::pmr::vector<std::pmr::vector<int>> outer_vec(std::pmr::get_default_resource());
std::pmr::vector<int> inner_vec(std::pmr::get_default_resource());
outer_vec.push_back(std::move(inner_vec));
And std::pmr::vector
can use emplace_back
to construct an element, such as:
std::pmr::vector<std::vector<int>> outer_vec(std::pmr::get_default_resource());
outer_vec.emplace_back();
Why does the combination of both fails? What static_assert
is failing?
Note that if the outer vector is not pmr
, it works:
std::vector<std::pmr::vector<int>> vec;
vec.emplace_back(std::pmr::get_default_resource());
CodePudding user response:
std::pmr::polymorphic_allocator
uses uses-allocator construction if supported by the constructed type. std::vector
does support uses-allocator construction and the allocator type of the inner std::vector
is compatible with that of the outer one.
In consequence uses-allocator construction will be used by the outer vector. This means, whenever the vector constructs a new element it will automatically pass its own allocator as another argument to the constructor of the element. (Specifically get_allocator()->resource()
is passed at the end of the argument list in this case.)
You are trying to pass an allocator manually to emplace_back
, so that in effect with the above two allocators will be passed to the inner vector's construction, resulting in failure.
So, what you really want is just outer_vec.emplace_back();
. It will propagate the outer vector's allocator to the inner vector.
Note that outer_vec.push_back(std::move(inner_vec));
will do the same. It will also propagate the outer allocator to the new "move"-constructed inner vector, resulting in moving all elements to a new allocation if necessary. It won't use the original allocation of inner_vec
if its allocator compares unequal to outer_vec
's allocator.