问题
I have a vector<vector<int>>
and want the entire memory (i.e., of both the outer and the inner vector) to be taken from a memory_resource
. Here is a stripped down example, first the boring part:
#include <boost/container/pmr/memory_resource.hpp>
#include <boost/container/scoped_allocator.hpp>
#include <boost/container/pmr/polymorphic_allocator.hpp>
#include <iostream>
#include <string>
#include <vector>
// Sample memory resource that prints debug information
class MemoryResource : public boost::container::pmr::memory_resource {
void* do_allocate(std::size_t bytes, std::size_t alignment) {
std::cout << "Allocate " << bytes << " bytes" << std::endl;
return malloc(bytes);
}
void do_deallocate(void* p, std::size_t bytes, std::size_t alignment) { free(p); }
bool do_is_equal(const memory_resource& other) const noexcept { return true; }
};
This is the part that I am interested in:
template <typename T>
using Alloc = boost::container::pmr::polymorphic_allocator<T>;
// using Alloc = std::allocator<T>;
template <typename T>
using PmrVector = std::vector<T, boost::container::scoped_allocator_adaptor<Alloc<T>>>;
using Inner = PmrVector<int>;
int main() {
MemoryResource resource{};
PmrVector<Inner> v(1000, Alloc<Inner>{&resource});
// PmrVector<Inner> v(1337, Alloc<Inner>{});
v[0].resize(100);
}
This gives me a lengthy compiler warning, essentially saying that it can't find a constructor for the inner vector.
If, instead of the polymorphic allocator, I use a regular allocator (e.g., std::allocator - see the lines that are commented out), everything seems to work.
The gcc error message is a bit better than that of clang:
/usr/local/include/boost/container/allocator_traits.hpp:415:10:
error: no matching function for call to '
std::vector<int, polymorphic_allocator<int> >::vector(
scoped_allocator_adaptor<...>&, polymorphic_allocator<...>&
)
'
Why would boost try to construct a vector by passing the allocator twice?
Also, here is a version that uses STL (experimental) instead of boost. That one gives an actual error message "construction with an allocator must be possible if uses_allocator is true", but that doesn't help me either.
Maybe I am understanding something conceptually wrong. Is this the way to do it or is there a better way to solve the original problem?
回答1:
Argh. The explanation is hidden in std::experimental::pmr::polymorphic_allocator::construct:
This function is called (through std::allocator_traits) by any allocator-aware object, such as std::vector, that was given a std::polymorphic_allocator as the allocator to use. Since memory_resource* implicitly converts to polymorphic_allocator, the memory resource pointer will propagate to any allocator-aware subobjects using polymorphic allocators.
So it turns out that polymorphic allocators automatically propagate. That also explains why the allocator is passed twice in the gcc error message.
Here is a working version:
template <typename T>
using Alloc = std::experimental::pmr::polymorphic_allocator<T>;
template <typename T>
using PmrVector = std::vector<T, Alloc<T>>;
using Inner = PmrVector<int>;
int main() {
MemoryResource resource{};
PmrVector<Inner> v(1000, Alloc<Inner>{&resource});
v[0].resize(100);
}
And here is the information that I would have need a couple of hours ago:
How do I use polymorphic_allocator and scoped_allocator_adaptor together?
You don't. Make sure that all inner containers also use polymorphic allocators, then the memory resource will be handed down automatically.
来源:https://stackoverflow.com/questions/54654606/c-cant-propagate-polymorphic-allocator-with-scoped-allocator-adaptor