Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/150.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ C++;11兼容线性分配器实现_C++_C++11_Memory Management_C++17_Allocator - Fatal编程技术网

C++ C++;11兼容线性分配器实现

C++ C++;11兼容线性分配器实现,c++,c++11,memory-management,c++17,allocator,C++,C++11,Memory Management,C++17,Allocator,我已经实现了一个与C++11兼容的线性或arena分配器。代码如下 线性分配器.hpp: #pragma once #include <cstddef> #include <cassert> #include <new> #include "aligned_mallocations.hpp" template <typename T> class LinearAllocator { public: using value_type =

我已经实现了一个与C++11兼容的线性或arena分配器。代码如下

线性分配器.hpp:

#pragma once

#include <cstddef>
#include <cassert>
#include <new>
#include "aligned_mallocations.hpp"

template <typename T>
class LinearAllocator
{
public:
    using value_type = T;
    using pointer = T*;
    using const_pointer = const T*;
    using reference = T&;
    using const_reference = const T&;
    //using propagate_on_container_copy_assignment = std::true_type;
    //using propagate_on_container_move_assignment = std::true_type;
    //using propagate_on_container_swap = std::true_type;

    LinearAllocator(std::size_t count = 64)
        : m_memUsed(0),
        m_memStartAddress(nullptr)
    {
        allocate(count);
    }
    ~LinearAllocator()
    {
        clear();
    }

    template <class U>
    LinearAllocator(const LinearAllocator<U>&) noexcept 
    {}

    /// \brief allocates memory equal to # count objects of type T
    pointer allocate(std::size_t count)
    {
        if (count > std::size_t(-1) / sizeof(T))
        {
            throw std::bad_alloc{};
        }
        if (m_memStartAddress != nullptr)
        {
            alignedFree(m_memStartAddress);
        }
        m_memUsed = count * sizeof(T);
        m_memStartAddress = static_cast<pointer>(alignedMalloc(m_memUsed, alignof(T)));
        return m_memStartAddress;
    }
    /// \brief deallocates previously allocated memory
    /// \brief Linear/arena allocators do not support free() operations. Use clear() instead.
    void deallocate([[maybe_unused]] pointer p, [[maybe_unused]] std::size_t count) noexcept
    {
        //assert(false);
        clear();
    }

    /// \brief simply resets memory
    void clear()
    {
        if (m_memStartAddress != nullptr)
        {
            alignedFree(m_memStartAddress);
            m_memStartAddress = nullptr;
        }
        this->m_memUsed = 0;
    }

    /// \brief GETTERS
    pointer getStartAddress() const
    {
        return this->m_memStartAddress;
    }
    std::size_t getUsedMemory() const
    {
        return this->m_memUsed;
    }
private:
    std::size_t m_memUsed;
    pointer m_memStartAddress;
};

template <class T, class U>
bool operator==(const LinearAllocator<T> &, const LinearAllocator<U> &)
{
    return true;
}

template <class T, class U>
bool operator!=(const LinearAllocator<T> &, const LinearAllocator<U> &)
{
    return false;
}
使用
g++-std=c++17-O2-march=native-Wall linear\u allocator.cpp-o linear\u allocator.gpp.exe编译并运行linear\u allocator.gpp.exe可提供以下输出:

0x4328b8
4096
Vector capacity = 100
Hello
w/e
whatever
there is ist sofi j
wisdom
fear
there's more than meets the eye
15LinearAllocatorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEE
正如您所看到的,deque的输出根本不存在。如果我取消注释这两行:

//std::cout << v.get_allocator().getStartAddress() << '\n';
//std::cout << v.get_allocator().getUsedMemory() << '\n';
更糟糕的是


一定有什么我错过了,因为似乎有UB,但我无法确定这是在哪里。我的分配器设计基于C++11+准则。我想知道我做错了什么。

虽然分配器负责提供和释放存储容器数据的内存,但它仍然只在容器请求时才这样做。也就是说,所提供存储的实际管理(特别是其生命周期)仍在容器一侧。想象一下,当向量重新定位其元素时会发生什么情况:

  • 请求一个比当前(旧)内存块更大的新内存块

  • 存储在“旧”块中的元素被复制/移动到新块中

  • 只有这样,“旧”内存块才能被释放

  • 在您的实现中,一次只能有一个内存块处于活动状态——在分配新内存块之前释放旧内存块(特别是,当容器只请求新内存块时,会发生这种情况,元素可以重新定位到新内存块)。当向量试图重新定位前一个存储中的元素时,您已经调用了UB,因为它们所在的内存已经失效

    此外,通过不为分配器类型提供复制构造函数,编译器提供的实现将执行浅层复制(即,它复制指针,而不是存储在该地址下的数据),然后在析构函数中释放。即呼吁:

    v.get_allocator()
    

    将创建分配器的浅层副本,创建分配器类型的prvalue,并在临时对象结束其生存期时(即,在包含
    cout
    调用的完整语句结束时)释放存储的指针,导致在同一指针上双重调用
    alignedFree

    我认为
    allocate
    不应该释放自己的内存。容器可以多次调用
    allocate
    deallocate
    ,以任意方式交错。但您似乎认为只有一个调用
    allocate
    与一个调用
    deallocate
    匹配;你的设计没有任何其他的方式。每次调用
    allocate
    时,都会丢弃整个旧块,使所有以前分配的和尚未解除分配的指针无效。我建议编写一个分配器,它只需委托给
    std::allocator
    进行实际的内存管理,但要记录
    allocate
    deallocate
    调用,这样您就可以看到一个典型的模式。@Nik Lz No。任何使用分配器的对象(容器)如果愿意,都会在内存中自行构造元素。分配器的副本不应制作和存储原始分配器拥有的元素的副本。如有必要,您应该复制对配置分配器或共享其状态有用的其他数据成员,因为分配器将被复制多次,但分配器的任何副本将主要用作内存源,而不是对象源。
    000000B47A1CAF88
    4096
    
    v.get_allocator()