1

タスク: T=buffer を指定した shared_ptr。ここで、バッファには動的な量のバイト (最後に uint8_t[]) があります。

allocate_shared は、この順序が保持されることを保証しますか: [shared_ptr data][object][additional butbuffer]

他の方法では機能しないため、たとえば: [object][shared_ptr data][additional butbuffer]

他の実装のアイデア?

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

2 に答える 2

2

コードはstd::allocate_sharedlibstdc++ の実装でも動作しますが、メモリ レイアウトがそのようになるという保証はないと思います。

を作成するために使用される特定の関数が既にあるため、カスタム アロケーター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));
    }
};

この方法では、アロケータ型が不要になり、維持するコードが少なくなり、コードがすべて 1 か所にまとめられます。これは、単一の割り当てのみを行うという利点を失いますallocate_shared(そして、オブジェクトに隣接するメタデータをカウントする shared_ptr ref を保持します)。

bufferこのコードは、コンストラクターがスローされないことに依存していcreateます。関数がスローされる可能性がある場合は、例外をキャッチし、メモリの割り当てを解除して再スローする必要があります。

bufferオブジェクトを関数によってのみ作成できるように、コンストラクターをプライベートにすることも検討しcreateます。

于 2012-12-29T15:20:28.197 に答える
0

結局、私は使用することにしました:

  • boost::intrusive_ptr with T = buffer
  • boost::atomic with T = std::size_t 参照カウント用 (ブーストの一部ではなく、別のライブラリ)

ポータブル単一割り当て。

于 2013-01-01T23:41:14.277 に答える