[英]MSVC std::_Container_base12 has wrong data in _Myproxy
[英]Custom C++ Allocator cause error in : _Container_base12::_Orphan_all_unlocked_v3()
所以我打算将这个基于堆栈的分配器用于 std::vector,并且我使用 2 arrays 进行分配(因为向量增长并将旧缓冲区复制到新缓冲区)。
这是完整的代码:
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <vector>
#include <cstddef>
#include <cassert>
#include <array>
using size_t = std::size_t;
using byte = std::byte;
template <class T, size_t capacity = 512>
class stack_allocator
{
public:
using value_type = T;
using pointer = value_type*;
using const_pointer = typename std::pointer_traits<pointer>::template rebind<value_type const>;
using void_pointer = typename std::pointer_traits<pointer>::template rebind<void>;
using const_void_pointer = typename std::pointer_traits<pointer>::template rebind<const void>;
using difference_type = typename std::pointer_traits<pointer>::difference_type;
using size_type = std::make_unsigned_t<difference_type>;
template <class U> struct rebind { typedef stack_allocator<U, capacity> other; };
stack_allocator() noexcept {}; // not required, unless used
~stack_allocator() noexcept = default;
//stack_allocator(stack_allocator&&) = delete;
//stack_allocator& operator=(stack_allocator&&) = delete;
//stack_allocator(const stack_allocator&) = delete;
//stack_allocator& operator=(const stack_allocator&) = delete;
template <class U>
stack_allocator(stack_allocator<U> const&) noexcept {}
// ? is n already aligned ?
inline pointer allocate(size_t n)
{
constexpr auto max_size_allowed = (capacity>>1);
auto size = n * sizeof(value_type);
if (size > max_size_allowed)
{
return static_cast<pointer>(::operator new (size));
}
else
{
m_Index = !m_Index;
return static_cast<pointer>(static_cast<void*>(&m_Array[static_cast<size_t>(m_Index)][0]));
}
}
inline void deallocate(pointer p, size_t n) noexcept
{
constexpr auto max_size_allowed = (capacity>>1);
auto size = n * sizeof(value_type);
if (size > max_size_allowed)
::operator delete(p);
else
{
// do nothing
}
}
inline pointer allocate(size_t n, const_void_pointer)
{
return allocate(n);
}
template <class U, class ...Args>
void construct(U* p, Args&& ...args)
{
::new(p) U(std::forward<Args>(args)...);
}
template <class U>
void destroy(U* p) noexcept
{
p->~U();
}
inline constexpr size_t max_size() const noexcept
{
return std::numeric_limits<std::size_t>::max() / sizeof(T);
}
stack_allocator select_on_container_copy_construction() const
{
return *this;
}
using propagate_on_container_copy_assignment = std::true_type;
using propagate_on_container_move_assignment = std::false_type;
using propagate_on_container_swap = std::true_type;
using is_always_equal = std::true_type;
protected:
//const bool is_pointer_in_range(byte* p) const noexcept { return (p >= &m_Array[0]) && (p <= &m_Array[capacity - 1]); }
bool m_Index{ false };
byte m_Array[2][(capacity >> 1)]{ {static_cast<byte>(0)} };
};
template <class T, size_t capacity, class U>
bool operator==(stack_allocator<T, capacity> const&, stack_allocator<U, capacity> const&) noexcept
{
return true;
}
template <class T, size_t capacity, class U>
bool operator!=(stack_allocator<T, capacity> const& x, stack_allocator<U, capacity> const& y) noexcept
{
return false;
}
int main(int argc, char** argv)
{
std::vector<int, stack_allocator<int, 512>> stackVec;
stackVec.push_back(1);
stackVec.push_back(2);
stackVec.push_back(3);
return 0;
}
代码以某种方式导致崩溃:在此处输入图像描述
我注意到“_Container_base12”继承自分配器,所以我想我的“stack_allocator”实现一定有问题。 但我想不通。
希望知道编写分配器的正确方法是什么。
多亏了Igor Tandetnik ,我才能够找出问题所在。 经过一番研究,我也发现,在 C++17 中其实很容易做到这一点,我们可以这样做:
std::array<unsigned char, 64> memory;
std::pmr::monotonic_buffer_resource pool{ memory.data(), memory.size() };
// then we can define our vector using stack memory
std::vector<int, std::pmr::polymorphic_allocator<int>> vec{&pool};
或者,我们可以将“std::array<unsigned char, 64> memory”放入自定义 memory_resource 中。
就我而言,我想对小对象使用就地数组以避免“分配”。 对于大对象,我想使用 pooled memory。
所以我继承了 _Identity_equal_resource 并在后台使用了一个全局的 unsynchronized_pool_resource。
现在一切对我来说都很完美。
// Note: still testing this.
template<size_t local_arena_size>
struct LocalArenaMemoryResource : public std::pmr::_Identity_equal_resource
{
private:
static inline constexpr size_t max_blocks_per_chunk = 16;
static inline constexpr size_t largest_required_pool_block = 16 * 1024;
static inline std::pmr::unsynchronized_pool_resource _pool{ std::pmr::pool_options { max_blocks_per_chunk, largest_required_pool_block } };
private:
using base = std::pmr::unsynchronized_pool_resource;
void* do_allocate(size_t _Bytes, size_t _Align) override
{
if (_Bytes <= local_arena_size)
{
return static_cast<void*>(&m_local_buffer[0]);
}
return _pool.allocate(_Bytes, _Align);
}
void do_deallocate(void* _Ptr, size_t _Bytes, size_t _Align) override
{
if (_Ptr >= &m_local_buffer[0] && _Ptr < &m_local_buffer[local_arena_size - 1])
{
// do nothing
}
else
{
_pool.deallocate(_Ptr, _Bytes, _Align);
}
}
private:
std::array<byte, local_arena_size> m_local_buffer;
};
有些事情我仍在学习,例如:当需要超大分配时,unsynchronized_pool_resource 如何处理分配。 另外我想知道 fixed_block_pool 是否会更有效率。 仍在学习,测试,但它真的很有趣。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.