Boost shared_ptr:如何使用自定义删除器和分配器

发布于 2024-09-13 00:46:40 字数 785 浏览 7 评论 0原文

自由函数allocate_shared可以与任何符合标准的分配器一起使用。但是shared_ptr的构造函数和reset方法呢?

template<class Y, class D, class A> shared_ptr(Y * p, D d, A a);
template<class Y, class D, class A> void reset(Y * p, D d, A a);

手册中说,D应该提供一个调用运算符,用于删除指针,并且A必须是一个符合标准的分配器。如果是这样,为什么需要DA 不能同时进行分配和解除分配吗? 您不认为为每个自定义分配器提供删除器的要求使得上述方法几乎毫无用处吗?当我使用自定义分配器时,我会选择allocate_shared。我如何知道释放自定义分配器分配的内存的正确方法是什么?

编辑:经过对逐字分配器和删除器的一些实验,我发现分配器传递给shared_ptr的构造函数和工厂函数allocate_shared > 仅用于分配shared_ptr的内部结构。 allocate_shared 从不使用传递的分配器来分配共享对象。我认为 boost 手册可以更明确地解释如何使用分配器。

Free function allocate_shared can be used with any standard compliant allocator. But what about shared_ptr's constructor and reset method.

template<class Y, class D, class A> shared_ptr(Y * p, D d, A a);
template<class Y, class D, class A> void reset(Y * p, D d, A a);

The manual says that D should provide a call operator which will be used to delete the pointer and A must be a standard compliant allocator. If so, why D is needed? Can't A do both allocation and delocation? Don't you think that the requirement to provide a deleter for every custom allocator makes the above methods pretty much useless? When I use custom allocators, I go for allocate_shared. How do I know what is the proper way to free memory allocated by a custom allocator?

EDIT: After some experimentation with a verbatim allocator and a deleter I figured out that the allocator passed to the constructor of shared_ptr and to the factory function allocate_shared is used to allocate the internal structure of shared_ptr only. allocate_shared never uses the passed allocator to allocate the shared object. I think that the boost manual could have explained how the allocator is used more explicitly.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

嘿哥们儿 2024-09-20 00:46:40

分配器旨在用于分配和释放内部shared_ptr详细信息,而不是对象。

也就是说,虽然删除器使我们能够完全控制共享对象(因为我们控制它的获取和释放方式),但分配器参数使我们能够控制对象共享性质的内部细节。

如果您查看N2351,在分配器提案的末尾,他们指出 Boost 已经实现了该功能,并链接到一个演示其用途的示例。

这是逐字的例子:

#include <boost/config.hpp>

//  shared_ptr_alloc2_test.cpp
//
//  Copyright (c) 2005 Peter Dimov
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)


#include <boost/detail/lightweight_test.hpp>
#include <boost/shared_ptr.hpp>
#include <memory>
#include <cstddef>

// test_allocator

struct test_allocator_base
{
    int id_;

    static int last_global_id_;
    static int count_;

    explicit test_allocator_base( int id ): id_( id )
    {
    }
};

int test_allocator_base::last_global_id_ = 0;
int test_allocator_base::count_ = 0;

template<class T> class test_allocator: public test_allocator_base
{
public:

    typedef T * pointer;
    typedef T const * const_pointer;
    typedef T & reference;
    typedef T const & const_reference;
    typedef T value_type;
    typedef std::size_t size_type;
    typedef std::ptrdiff_t difference_type;

private:

    static T * last_pointer_;
    static std::size_t last_n_;
    static int last_id_;

public:

    template<class U> struct rebind
    {
        typedef test_allocator<U> other;
    };

    pointer address( reference r ) const
    {
        return &r;
    }

    const_pointer address( const_reference s ) const
    {
        return &s;
    }

    explicit test_allocator( int id = 0 ): test_allocator_base( id )
    {
    }

    template<class U> test_allocator( test_allocator<U> const & r ): test_allocator_base( r )
    {
    }

    template<class U> test_allocator & operator=( test_allocator<U> const & r )
    {
        test_allocator_base::operator=( r );
        return *this;
    }

    void deallocate( pointer p, size_type n )
    {
        BOOST_TEST( p == last_pointer_ );
        BOOST_TEST( n == last_n_ );
        BOOST_TEST( id_ == last_id_ );

        --count_;

        ::operator delete( p );
    }

    pointer allocate( size_type n, void const * )
    {
        T * p = static_cast< T* >( ::operator new( n * sizeof( T ) ) );

        last_pointer_ = p;
        last_n_ = n;
        last_id_ = id_;

        last_global_id_ = id_;
        ++count_;

        return p;
    }

    void construct( pointer p, T const & t )
    {
        new( p ) T( t );
    }

    void destroy( pointer p )
    {
        p->~T();
    }

    size_type max_size() const
    {
        return size_type( -1 ) / sizeof( T );
    }
};

template<class T> T * test_allocator<T>::last_pointer_ = 0;
template<class T> std::size_t test_allocator<T>::last_n_ = 0;
template<class T> int test_allocator<T>::last_id_ = 0;

template<class T, class U> inline bool operator==( test_allocator<T> const & a1, test_allocator<U> const & a2 )
{
    return a1.id_ == a2.id_;
}

template<class T, class U> inline bool operator!=( test_allocator<T> const & a1, test_allocator<U> const & a2 )
{
    return a1.id_ != a2.id_;
}

template<> class test_allocator<void>: public test_allocator_base
{
public:

    typedef void * pointer;
    typedef void const * const_pointer;
    typedef void value_type;

    template<class U> struct rebind
    {
        typedef test_allocator<U> other;
    };

    explicit test_allocator( int id = 0 ): test_allocator_base( id )
    {
    }

    template<class U> test_allocator( test_allocator<U> const & r ): test_allocator_base( r )
    {
    }

    template<class U> test_allocator & operator=( test_allocator<U> const & r )
    {
        test_allocator_base::operator=( r );
        return *this;
    }
};

//

struct X
{
    static int instances;

    X()
    {
        ++instances;
    }

    ~X()
    {
        --instances;
    }

private:

    X( X const & );
    X & operator=( X const & );
};

int X::instances = 0;

int main()
{
    BOOST_TEST( X::instances == 0 );

    boost::shared_ptr<void> pv( new X, boost::checked_deleter<X>(), std::allocator<X>() );

    BOOST_TEST( X::instances == 1 );

    pv.reset( new X, boost::checked_deleter<X>(), test_allocator<float>( 42 ) );

    BOOST_TEST( X::instances == 1 );

    BOOST_TEST( test_allocator_base::last_global_id_ == 42 );
    BOOST_TEST( test_allocator_base::count_ > 0 );

    pv.reset();

    BOOST_TEST( X::instances == 0 );
    BOOST_TEST( test_allocator_base::count_ == 0 );

    pv.reset( new X, boost::checked_deleter<X>(), test_allocator<void>( 43 ) );

    BOOST_TEST( X::instances == 1 );
    BOOST_TEST( test_allocator_base::last_global_id_ == 43 );

    pv.reset( new X, boost::checked_deleter<X>(), std::allocator<void>() );

    BOOST_TEST( X::instances == 1 );

    pv.reset();

    BOOST_TEST( X::instances == 0 );

    return boost::report_errors();
}

The allocator is intended to be used to allocate and deallocate internal shared_ptr details, not the object.

That is, while the deleter gives us full control over our shared object (because we control how it's acquired and released), the allocator parameter gives us control over the internal details of our object's shared nature.

If you look at N2351, at the end of the allocator proposal they note that Boost has implemented the feature, and link to an example that was made to demonstrate its use.

Here is that example, verbatim:

#include <boost/config.hpp>

//  shared_ptr_alloc2_test.cpp
//
//  Copyright (c) 2005 Peter Dimov
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)


#include <boost/detail/lightweight_test.hpp>
#include <boost/shared_ptr.hpp>
#include <memory>
#include <cstddef>

// test_allocator

struct test_allocator_base
{
    int id_;

    static int last_global_id_;
    static int count_;

    explicit test_allocator_base( int id ): id_( id )
    {
    }
};

int test_allocator_base::last_global_id_ = 0;
int test_allocator_base::count_ = 0;

template<class T> class test_allocator: public test_allocator_base
{
public:

    typedef T * pointer;
    typedef T const * const_pointer;
    typedef T & reference;
    typedef T const & const_reference;
    typedef T value_type;
    typedef std::size_t size_type;
    typedef std::ptrdiff_t difference_type;

private:

    static T * last_pointer_;
    static std::size_t last_n_;
    static int last_id_;

public:

    template<class U> struct rebind
    {
        typedef test_allocator<U> other;
    };

    pointer address( reference r ) const
    {
        return &r;
    }

    const_pointer address( const_reference s ) const
    {
        return &s;
    }

    explicit test_allocator( int id = 0 ): test_allocator_base( id )
    {
    }

    template<class U> test_allocator( test_allocator<U> const & r ): test_allocator_base( r )
    {
    }

    template<class U> test_allocator & operator=( test_allocator<U> const & r )
    {
        test_allocator_base::operator=( r );
        return *this;
    }

    void deallocate( pointer p, size_type n )
    {
        BOOST_TEST( p == last_pointer_ );
        BOOST_TEST( n == last_n_ );
        BOOST_TEST( id_ == last_id_ );

        --count_;

        ::operator delete( p );
    }

    pointer allocate( size_type n, void const * )
    {
        T * p = static_cast< T* >( ::operator new( n * sizeof( T ) ) );

        last_pointer_ = p;
        last_n_ = n;
        last_id_ = id_;

        last_global_id_ = id_;
        ++count_;

        return p;
    }

    void construct( pointer p, T const & t )
    {
        new( p ) T( t );
    }

    void destroy( pointer p )
    {
        p->~T();
    }

    size_type max_size() const
    {
        return size_type( -1 ) / sizeof( T );
    }
};

template<class T> T * test_allocator<T>::last_pointer_ = 0;
template<class T> std::size_t test_allocator<T>::last_n_ = 0;
template<class T> int test_allocator<T>::last_id_ = 0;

template<class T, class U> inline bool operator==( test_allocator<T> const & a1, test_allocator<U> const & a2 )
{
    return a1.id_ == a2.id_;
}

template<class T, class U> inline bool operator!=( test_allocator<T> const & a1, test_allocator<U> const & a2 )
{
    return a1.id_ != a2.id_;
}

template<> class test_allocator<void>: public test_allocator_base
{
public:

    typedef void * pointer;
    typedef void const * const_pointer;
    typedef void value_type;

    template<class U> struct rebind
    {
        typedef test_allocator<U> other;
    };

    explicit test_allocator( int id = 0 ): test_allocator_base( id )
    {
    }

    template<class U> test_allocator( test_allocator<U> const & r ): test_allocator_base( r )
    {
    }

    template<class U> test_allocator & operator=( test_allocator<U> const & r )
    {
        test_allocator_base::operator=( r );
        return *this;
    }
};

//

struct X
{
    static int instances;

    X()
    {
        ++instances;
    }

    ~X()
    {
        --instances;
    }

private:

    X( X const & );
    X & operator=( X const & );
};

int X::instances = 0;

int main()
{
    BOOST_TEST( X::instances == 0 );

    boost::shared_ptr<void> pv( new X, boost::checked_deleter<X>(), std::allocator<X>() );

    BOOST_TEST( X::instances == 1 );

    pv.reset( new X, boost::checked_deleter<X>(), test_allocator<float>( 42 ) );

    BOOST_TEST( X::instances == 1 );

    BOOST_TEST( test_allocator_base::last_global_id_ == 42 );
    BOOST_TEST( test_allocator_base::count_ > 0 );

    pv.reset();

    BOOST_TEST( X::instances == 0 );
    BOOST_TEST( test_allocator_base::count_ == 0 );

    pv.reset( new X, boost::checked_deleter<X>(), test_allocator<void>( 43 ) );

    BOOST_TEST( X::instances == 1 );
    BOOST_TEST( test_allocator_base::last_global_id_ == 43 );

    pv.reset( new X, boost::checked_deleter<X>(), std::allocator<void>() );

    BOOST_TEST( X::instances == 1 );

    pv.reset();

    BOOST_TEST( X::instances == 0 );

    return boost::report_errors();
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文