(23.2.1 – 3)
For the components affected by this subclause that declare an allocator_type,objects stored in these components shall be constructed using the allocator_traits::construct function and destroyed using the allocator_traits::destroy function (20.6.8.2). These functions are called only for the container’s element type,not for internal types used by the container
(23.2.1 – 7)
Unless otherwise specified,all containers defined in this clause obtain memory using an allocator
是否真的,容器使用的所有内存都是由指定的分配器分配的?因为标准说内部类型不是用allocator_traits :: construct构造的,所以应该对operator new进行某种调用.但是标准也说这个子句中定义的所有容器都使用分配器来获取内存,在我看来这意味着它不能是普通的新运算符,它必须是放置新的运算符.我对么?
让我举个例子,为什么这很重要.
假设我们有一个类,它包含一些已分配的内存:
#include <unordered_map> #include <iostream> #include <cstdint> #include <limits> #include <memory> #include <new> class Arena { public: Arena(std::size_t size) { size_ = size; location_ = 0; data_ = nullptr; if(size_ > 0) data_ = new(std::nothrow) uint8_t[size_]; } Arena(const Arena& other) = delete; ~Arena() { if(data_ != nullptr) delete[] data_; } Arena& operator =(const Arena& arena) = delete; uint8_t* allocate(std::size_t size) { if(data_ == nullptr) throw std::bad_alloc(); if((location_ + size) >= size_) throw std::bad_alloc(); uint8_t* result = &data_[location_]; location_ += size; return result; } void clear() { location_ = 0; } std::size_t getNumBytesUsed() const { return location_; } private: uint8_t* data_; std::size_t location_,size_; };
我们也有自定义分配器:
template <class T> class FastAllocator { public: typedef T value_type; typedef T* pointer; typedef const T* const_pointer; typedef T& reference; typedef const T& const_reference; typedef std::size_t size_type; typedef std::ptrdiff_t difference_type; template <class U> class rebind { public: typedef FastAllocator<U> other; }; Arena* arena; FastAllocator(Arena& arena_): arena(&arena_) {} FastAllocator(const FastAllocator& other): arena(other.arena) {} template <class U> FastAllocator(const FastAllocator<U>& other): arena(other.arena) {} //------------------------------------------------------------------------------------ pointer allocate(size_type n,std::allocator<void>::const_pointer) { return allocate(n); } pointer allocate(size_type n) { return reinterpret_cast<pointer>(arena->allocate(n * sizeof(T))); } //------------------------------------------------------------------------------------ void deallocate(pointer,size_type) {} //------------------------------------------------------------------------------------ size_type max_size() const { return std::numeric_limits<size_type>::max(); } //------------------------------------------------------------------------------------ void construct(pointer p,const_reference val) { ::new(static_cast<void*>(p)) T(val); } template <class U> void destroy(U* p) { p->~U(); } };
这就是我们使用它的方式:
typedef std::unordered_map<uint32_t,uint32_t,std::hash<uint32_t>,std::equal_to<uint32_t>,FastAllocator<std::pair<uint32_t,uint32_t>>> FastUnorderedMap; int main() { // Allocate memory in arena Arena arena(1024 * 1024 * 50); FastAllocator<uint32_t> allocator(arena); FastAllocator<std::pair<uint32_t,uint32_t>> pairAllocator(arena); FastAllocator<FastUnorderedMap> unorderedMapAllocator(arena); FastUnorderedMap* fastUnorderedMap = nullptr; try { // allocate memory for unordered map fastUnorderedMap = unorderedMapAllocator.allocate(1); // construct unordered map fastUnorderedMap = new(reinterpret_cast<void*>(fastUnorderedMap)) FastUnorderedMap ( 0,std::hash<uint32_t>(),std::equal_to<uint32_t>(),pairAllocator ); // insert something for(uint32_t i = 0; i < 1000000; ++i) fastUnorderedMap->insert(std::make_pair(i,i)); } catch(std::bad_alloc badAlloc) { std::cout << "--- BAD ALLOC HAPPENED DURING FAST UNORDERED MAP INSERTION ---" << std::endl; } // no destructor of unordered map is called!!!! return 0; }
如您所见,unordered_map的析构函数永远不会被调用,但在破坏竞技场对象期间会释放内存.会有任何内存泄漏吗?为什么?
我真的很感激这个主题的任何帮助.