带有附加字节缓冲区的Allocate_shared

allocate_shared with additional byte buffer

本文关键字:Allocate shared 缓冲区 字节      更新时间:2023-10-16

任务:shared_ptr with T=buffer,其中buffer具有动态字节数(末尾为uint8_t[]);

是否allocate_shared保证这个顺序将被保留:[shared_ptr data][object][additional butebuffer]

因为其他方式不起作用,例如:[object][shared_ptr data][add butebuffer]

其他实现思路?

template <class T>
class addon_allocator : public boost::noncopyable
{
public : 
    typedef T value_type;
    typedef value_type* pointer;
    typedef const value_type* const_pointer;
    typedef value_type& reference;
    typedef const value_type& const_reference;
    typedef std::size_t size_type;
    typedef std::ptrdiff_t difference_type;
public : 
    template<typename U> struct rebind
    {
        typedef addon_allocator<U> other;
    };
public : 
    explicit addon_allocator( std::size_t size )
        :m_size( size )
    {
    }
    ~addon_allocator()
    {
    }
    addon_allocator(const addon_allocator<T>& other)
        :m_size(other.m_size)
    {
    }
    template <class U>
    explicit addon_allocator(const addon_allocator<U>& other)
        :m_size(other.get_addon_size())
    {
    }
    pointer address(reference r)
    {
        return &r;
    }
    const_pointer address(const_reference r)
    {
        return &r;
    }
    pointer allocate(size_type cnt, typename std::allocator<void>::const_pointer = 0)
    {
        assert( cnt == 1 );
        return reinterpret_cast<pointer>(
            ::operator new(sizeof(T) + m_size)
            );
    }
    void deallocate(pointer p, size_type)
    {
        ::operator delete(p);
    }
    std::size_t get_addon_size() const
    {
        return m_size;
    }
private:
    const std::size_t m_size;
};
class buffer : public boost::noncopyable
{
public:
    buffer( std::size_t size )
        :m_size(size)
    {
    }
    const std::size_t m_size;
    uint8_t m_data[];
    static boost::shared_ptr<buffer> create(std::size_t size)
    {
        boost::allocate_shared<buffer>(
            addon_allocator<buffer>(size),
            size
            );
    }
};

你的代码也将与std::allocate_shared在libstdc++中的实现一起工作,但我不认为有任何保证内存布局将是那样的。

由于您已经有一个用于创建shared_ptr的特定函数,因此手动进行内存分配比在自定义分配器中使用allocate_shared更可移植:

class buffer : public boost::noncopyable
{
public:
    buffer( std::size_t size ) throw()
        :m_size(size)
    {
    }
    const std::size_t m_size;
    uint8_t m_data[];
    static boost::shared_ptr<buffer> create(std::size_t size)
    {
        void* addr = ::operator new(sizeof(buffer) + size);
        return boost::shared_ptr<buffer>(::new(addr) buffer(size));
    }
};

这样就不需要分配器类型,需要维护的代码更少,而且代码都在一个地方。这确实失去了allocate_shared只进行单个分配的优势(并保持shared_ptr refcounting元数据与对象相邻),但它保证在任何实现上都能工作……这取决于你是否值得。

此代码依赖于buffer构造函数为无抛出,如果它可以抛出create函数,则需要捕获异常,释放内存并重新抛出。

我还会考虑将构造函数设为私有,以便buffer对象只能由create函数创建。

最后我决定使用:

  • boost::intrusive_ptr with T = buffer
  • boost::atomic with T = std::size_t用于引用计数(不是boost的一部分,单独的库)

可移植的单分配。