c – 容器使用的内部类型的内存分配

c – 容器使用的内部类型的内存分配,第1张

概述C 11标准在一般集装箱要求中有以下几行. (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::con C 11标准在一般集装箱要求中有以下几行.

(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的析构函数永远不会被调用,但在破坏竞技场对象期间会释放内存.会有任何内存泄漏吗?为什么?

我真的很感激这个主题的任何帮助.

解决方法 分配器应该提供4个功能(这里感兴趣):

> 2用于内存管理:分配/解除分配
> 2用于对象生存期管理:construct / destroy

引用中的这些函数仅适用于构造和销毁(在前一句中提到),而不是分配/解除分配,因此没有矛盾.

现在,关于内存泄漏,竞技场分配器不仅应该使用竞技场分配器(容器保证)来构建容器中的对象,而且还应该从该分配器获得这些对象分配的所有内存;不幸的是,这会变得稍微复杂一些.

总结

以上是内存溢出为你收集整理的c – 容器使用的内部类型的内存分配全部内容,希望文章能够帮你解决c – 容器使用的内部类型的内存分配所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/langs/1257752.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-06-07
下一篇 2022-06-07

发表评论

登录后才能评论

评论列表(0条)

保存