【问题标题】:allocate_shared with additional byte bufferallocate_shared 与额外的字节缓冲区
【发布时间】:2012-12-22 14:03:20
【问题描述】:

Task:shared_ptr with T=buffer,其中buffer有动态字节数(uint8_t[]结尾);

allocate_shared 是否保证此订单将被保留: [shared_ptr 数据][对象][附加缓冲区]

因为其他方式不起作用,例如: [对象][shared_ptr 数据][附加缓冲区]

其他实现思路?

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
            );
    }
};

【问题讨论】:

  • 我的想法?我想要单个分配缓冲区,它正在工作,但可能会停止,如果在下一个实现中将 20 字节的 allocate_shared 标头移动到对象之后(而不是之前,就像现在)。
  • 我不是 boost 方面的专家,但在我看来是合理的。

标签: c++ boost shared-ptr


【解决方案1】:

您的代码也可以在 libstdc++ 中使用 std::allocate_shared 的实现,但我认为不能保证内存布局会是这样。

由于您已经拥有用于创建 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 ref 计数与对象相邻的元数据),但它保证适用于任何实现......这取决于你是否值得权衡它。

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

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

【讨论】:

    【解决方案2】:

    最后我决定使用:

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

    便携式单一分配。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-01-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-12-18
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多