2010-07-31 131 views
3

自由功能allocate_shared可與任何符合標準的分配器一起使用。但是shared_ptr的構造函數和重置方法呢?Boost shared_ptr:如何使用自定義刪除器和分配器

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應提供將用於刪除指針和必須是符合標準規範的分配器的呼叫操作員。如果是這樣,爲什麼需要D?不能A做分配和分配? 您不認爲爲每個自定義分配器提供刪除器的要求使上述方法幾乎無用嗎?當我使用自定義分配器時,我去找allocate_shared。我怎麼知道什麼是釋放自定義分配器分配內存的正確方法?

編輯:後一些實驗用逐字分配器和一個刪除器我想出傳遞給的shared_ptr的構造和工廠功能分配器allocate_shared用於分配的shared_ptr的內部結構僅限allocate_shared從不使用傳遞的分配器來分配共享對象。我認爲boost手冊可以解釋如何更明確地使用分配器。

+0

部分是不正確的。 'allocate_shared'不僅用於'shared_ptr'控制塊的分配器,還用於對象本身!它利用'allocator :: rebind'來獲得一個「兄弟分配器」,它將分配足夠大的內存塊來保存對象以及其控制塊。 – 2012-05-07 09:57:30

回答

6

該分配器旨在用於分配和釋放內部shared_ptr詳細信息,而不是對象。也就是說,雖然deleter讓我們完全控制我們的共享對象(因爲我們控制了它的獲取和釋放方式),但allocator參數讓我們可以控制對象的共享特性的內部細節。

如果你看看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(); 
} 
+0

** allocate_shared **怎麼樣?它是否使用分配器來分配內部和指針? – user401947 2010-08-01 06:25:07

+0

@ rn141:不,它只是給你分配的'shared_ptr'。基本上,非分配器的構造函數是'make_shared',因爲分配器的構造函數是'allocate_shared'。 – GManNickG 2010-08-01 06:41:42

+0

對不起,我不明白。 ** allocate_shared **如何使用作爲參數傳遞的分配器? ** allocate_shared **是否使用它來分配指針? ** allocate_shared **是否使用它來分配引用計數?你說刪除者讓我們完全控制共享對象。但手冊中說,刪除程序只用於刪除,而不是分配。 – user401947 2010-08-01 15:42:36

相關問題