Skip to content

Instantly share code, notes, and snippets.

@gintenlabo
Created November 24, 2010 14:00
Show Gist options
  • Save gintenlabo/713685 to your computer and use it in GitHub Desktop.
Save gintenlabo/713685 to your computer and use it in GitHub Desktop.
カスタム削除子を指定可能 && 所有するポインタを release 出来る、俺々 scoped_ptr
/*
default_delete : std::default_delete の移植
boost::checked_delete を使って削除する deleter です。
配列の場合は checked_array_delete を使います。
定義を見れば一目瞭然。
*/
#ifndef ETUDE_INCLUDED_DEFAULT_DELETE_HPP_
#define ETUDE_INCLUDED_DEFAULT_DELETE_HPP_
#include <boost/checked_delete.hpp>
namespace etude {
template<class T>
struct default_delete
{
typedef void result_type;
typedef T* argument_type;
void operator()( T* p ) const {
boost::checked_delete(p);
}
};
template<class T>
struct default_delete<T[]>
{
typedef void result_type;
typedef T* argument_type;
void operator()( T* p ) const {
boost::checked_array_delete(p);
}
};
} // namespace etude
#endif // #ifndef ETUDE_INCLUDED_DEFAULT_DELETE_HPP_
/*
move_ptr : std::auto_ptr のカスタム削除子指定可能版
機能:
etude::scoped_ptr だけだと色々と面倒なので、
所有権移動のための補助クラスとして製作したクラス。
一応スマートポインタとしても使えるようにしてありますが、
std::auto_ptr と同じ弱点を持ってるため、使用は非推奨です。
*/
#ifndef ETUDE_INCLUDED_MOVE_PTR_HPP_
#define ETUDE_INCLUDED_MOVE_PTR_HPP_
#include <memory>
#include <boost/compressed_pair.hpp>
#include <boost/noncopyable.hpp>
#include "default_delete.hpp"
#include "pointer_facade.hpp"
namespace etude {
namespace detail_ {
template<class T, class D>
struct move_ptr_ref
{
typedef typename pointer_types<T>::pointer pointer;
typedef D deleter;
move_ptr_ref()
: pair_( static_cast<pointer>(0) ) {}
move_ptr_ref( pointer p, deleter d )
: pair_( p, d ) {}
template<class U, class E>
move_ptr_ref( move_ptr_ref<U, E> const& src )
: pair_( src.pair_ ) {}
boost::compressed_pair<pointer, deleter> pair_;
};
template<class T, class D>
struct move_ptr_impl
: private boost::noncopyable
{
typedef typename pointer_types<T>::pointer pointer;
typedef D deleter;
move_ptr_impl()
: impl_( static_cast<pointer>(0) ) {}
explicit move_ptr_impl( deleter d )
: impl_( static_cast<pointer>(0), d ) {}
// from pointers
explicit move_ptr_impl( pointer p )
: impl_( p ) {}
move_ptr_impl( pointer p, deleter d )
: impl_( p, d ) {}
// from move_ptr_ref
template<class U, class E>
move_ptr_impl( move_ptr_ref<U, E> const& x )
: impl_( x.pair_ ) {}
template<class U, class E>
move_ptr_impl& operator=( move_ptr_ref<U, E> const& rhs ) {
impl_ = rhs.pair_;
return *this;
}
// to move_ptr_ref
move_ptr_ref<T, D> move() {
move_ptr_ref<T, D> ref;
impl_.swap( ref.pair_ );
return ref;
}
// destory
~move_ptr_impl() {
pointer const p = get_pointer();
if( p ) {
deleter& d = get_deleter();
d(p);
}
}
// modifiers
void swap( move_ptr_impl& other ) {
impl_.swap( other.impl_ );
}
pointer release() {
pointer const p = impl_.first();
impl_.first() = 0;
return p;
}
// observers
// pointer access
pointer get_pointer() const { return impl_.first(); }
// deleter access
deleter& get_deleter() { return impl_.second(); }
deleter const& get_deleter() const { return impl_.second(); }
private:
boost::compressed_pair<pointer, deleter> impl_;
};
struct move_ptr_category {};
} // namespace detail_
// move_ptr : advanced std::auto_ptr
// this is a helper class template for etude::scoped_ptr;
// uses by itself are deprecated.
template< class T, class Deleter = etude::default_delete<T> >
struct move_ptr
: pointer_facade< move_ptr<T, Deleter>, T, detail_::move_ptr_category >
{
typedef typename pointer_types<T>::pointer pointer;
typedef Deleter deleter;
typedef typename pointer_types<T>::element_type element_type;
typedef Deleter deleter_type;
// construct/destory
// default-construct
move_ptr()
: impl_() {}
explicit move_ptr( deleter d )
: impl_( d ) {}
// from pointers
explicit move_ptr( pointer p )
: impl_( p ) {}
move_ptr( pointer p, deleter d )
: impl_( p, d ) {}
// destory
~move_ptr() {}
// move constructors
move_ptr( move_ptr& src ) {
src.swap( *this );
}
template<class U, class D>
move_ptr( move_ptr<U, D>& src )
: impl_( src.release(), src.get_deleter() ) {}
// move assignment
move_ptr& operator=( move_ptr& rhs ) {
move_ptr(rhs).swap(*this);
return *this;
}
template<class U, class D>
move_ptr& operator=( move_ptr<U, D>& rhs ) {
move_ptr(rhs).swap(*this);
return *this;
}
// from std::auto_ptr
template<class U>
move_ptr( std::auto_ptr<U> src )
: impl_( src.release() ) {}
template<class U>
move_ptr( std::auto_ptr<U> src, Deleter d )
: impl_( src.release(), d ) {}
template<class U>
move_ptr& operator=( std::auto_ptr<U> rhs ) {
move_ptr(rhs).swap(*this);
return *this;
}
// modifiers
void swap( move_ptr& other ) {
impl_.swap( other.impl_ );
}
friend void swap( move_ptr& one, move_ptr& another ) {
one.swap( another );
}
void reset() {
move_ptr().swap(*this);
}
void reset( pointer p ) {
move_ptr(p).swap(*this);
}
void reset( pointer p, deleter d ) {
move_ptr( p, d ).swap(*this);
}
pointer release() {
return impl_.release();
}
// observers
// pointer access
pointer get_pointer() const { return impl_.get_pointer(); }
// deleter access
deleter& get_deleter() { return impl_.get_deleter(); }
deleter const& get_deleter() const { return impl_.get_deleter(); }
// other observers are generated by pointer_facade
// Colvin-Gibbons trick
move_ptr( detail_::move_ptr_ref<T, Deleter> const& src )
: impl_( src ) {}
move_ptr& operator=( detail_::move_ptr_ref<T, Deleter> const& rhs ) {
impl_ = rhs;
return *this;
}
template<class U, class D>
operator detail_::move_ptr_ref<U, D>() {
return impl_.move();
}
private:
detail_::move_ptr_impl<T, Deleter> impl_;
};
// helper function
template<class T>
move_ptr<T> scoped( T* p ) {
return move_ptr<T>(p);
}
template<class T, class D>
move_ptr<T, D> scoped( T* p, D d ) {
return move_ptr<T, D>( p, d );
}
} // namespace etude
#endif // #ifndef ETUDE_INCLUDED_MOVE_PTR_HPP_
/*
pointer_facade : 簡易スマートポインタ製作
機能:
get_pointer() さえ実装すれば、それを元にスマートポインタとして必要なものを生成するクラスです。
実装してくれるものは以下の通り:
 ・element_type, value_type, pointer, reference の型定義
 ・get, operator*, operator->, get_pointer(friend関数) によるポインタ取得
 ・bool値との比較、スマートポインタ同士の比較
 ・異なる型を示すスマートポインタ同士の比較(同じカテゴリに属するもののみ)
使い方は「テンプレートに自分自身の型名を入れて継承」。
第二引数はポインタを格納するオブジェクトの型を示します。
省略可能な第三引数はポインタのカテゴリ、第三引数が同じスマートポインタ同士は相互比較できます。
省略した場合、他のスマートポインタとは比較が出来ません。
また、第二引数として T[] を指定すると、operator* と operator-> の代わりに
operator[] と operator+ が定義されるようになります。
*/
#ifndef ETUDE_INCLUDED_POINTER_FACADE_HPP_
#define ETUDE_INCLUDED_POINTER_FACADE_HPP_
#include <functional> // for std::less
#include <boost/assert.hpp>
#include "pointer_types.hpp"
namespace etude
{
namespace pointer_facade_ // ADL 回避
{
// スマートポインタ生成ファクトリ
template< typename Derived, typename T, typename Category = Derived >
class pointer_facade
{
typedef etude::pointer_types<T> types_;
public:
// スマートポインタとして必要な typedef
typedef typename types_::element_type element_type;
typedef typename types_::value_type value_type;
typedef typename types_::pointer pointer;
typedef typename types_::reference reference;
// get() は派生クラスの get_pointer() を呼び出す
pointer get() const {
return static_cast<Derived const*>(this)->get_pointer();
}
// 参照外しとポインタ取得
reference operator*() const {
pointer const p = get();
BOOST_ASSERT( p != 0 );
return *p;
}
pointer operator->() const {
pointer const p = get();
BOOST_ASSERT( p != 0 );
return p;
}
// for boost::mem_fn
friend pointer get_pointer( Derived const& target ) {
return target.get_pointer();
}
// bool との比較
typedef pointer (pointer_facade::*bool_type)() const;
operator bool_type() const {
return get() ? &pointer_facade::get : 0;
}
bool operator!() const {
return !get();
}
// 相互比較は外部で定義する
protected:
pointer_facade(){}
}; // pointer_facade<Derived, T, Category>
// 配列版
template< typename Derived, typename T, typename Category >
class pointer_facade<Derived, T[], Category>
{
typedef etude::pointer_types<T[]> types_;
public:
// スマートポインタとして必要な typedef
typedef typename types_::element_type element_type;
typedef typename types_::value_type value_type;
typedef typename types_::pointer pointer;
typedef typename types_::reference reference;
// get() は派生クラスの get_pointer() を呼び出す
pointer get() const {
return static_cast<Derived const*>(this)->get_pointer();
}
// 配列用の演算に
reference operator[]( std::size_t i ) const {
pointer const p = get();
BOOST_ASSERT( p != 0 );
return p[i];
}
pointer operator+( std::size_t i ) const {
pointer const p = get();
BOOST_ASSERT( p != 0 );
return p + i;
}
// for boost::mem_fn
friend pointer get_pointer( Derived const& target ) {
return target.get_pointer();
}
// bool との比較
typedef pointer (pointer_facade::*bool_type)() const;
operator bool_type() const {
return get() ? &pointer_facade::get : 0;
}
bool operator!() const {
return !get();
}
// 相互比較は外部で定義
protected:
pointer_facade(){}
};
// 相互比較
// カテゴリが同じものなら相互比較OK
template<typename T, typename U, typename D1, typename D2, typename C>
inline bool operator==( const pointer_facade<D1, T, C>& lhs, const pointer_facade<D2, U, C>& rhs )
{
return lhs.get() == rhs.get();
}
template<typename T, typename U, typename D1, typename D2, typename C>
inline bool operator!=( pointer_facade<D1, T, C> const& lhs, pointer_facade<D2, U, C> const& rhs )
{
return lhs.get() != rhs.get();
}
// < は、ポインタ型が同じ場合とそうでない場合で分ける
template<typename T, typename D, typename C>
inline bool operator< ( pointer_facade<D, T, C> const& lhs, pointer_facade<D, T, C> const& rhs )
{
// 同じポインタの比較は std::less で比較する
return std::less<T*>()( lhs.get(), rhs.get() );
}
template<typename T, typename U, typename D1, typename D2, typename C>
inline bool operator< ( const pointer_facade<D1, T, C>& lhs, const pointer_facade<D2, U, C>& rhs )
{
// 異なるポインタ同士の比較は、仕方ないので < で比較する
return lhs.get() < rhs.get();
}
} // namespace pointer_facade_
// 名前空間に引き入れる
using namespace pointer_facade_;
} // namespace etude
#endif // #ifndef ETUDE_INCLUDED_POINTER_FACADE_HPP_
/*
pointer_types : poiter_facade 用の型定義
機能:
見たとおり、スマートポインタ用の型定義です。
これはそのまま pointer_facade に使われます。
これを pointer_facade とは別のクラスにすることにより、
typedef typename etude::pointer_facade<xxx_ptr, T, category>::reference reference;
とかいう面倒な typedef を、より単純な
typedef typename etude::pointer_types<T>::reference reference;
に置き換えることが可能になります。
*/
#ifndef ETUDE_INCLUDED_POINTER_TYPES_HPP_
#define ETUDE_INCLUDED_POINTER_TYPES_HPP_
#include <boost/type_traits/add_reference.hpp>
namespace etude
{
template<class T>
struct pointer_types {
typedef T element_type;
typedef T value_type;
typedef T* pointer;
typedef typename boost::add_reference<T>::type reference; // void 対策
};
template<class T>
struct pointer_types<T[]> {
typedef T element_type;
typedef T value_type;
typedef T* pointer;
typedef T& reference; // void[] なんてものは仮に存在したとしてもエラーがお似合い
};
} // namespace etude
#endif // #ifndef ETUDE_INCLUDED_POINTER_TYPES_HPP_
#include "scoped_ptr.hpp"
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <boost/noncopyable.hpp>
struct hoge
: private boost::noncopyable
{
hoge( int i_ )
: i(i_)
{
std::cout << "hoge (" << i << "): Hello!\n";
}
~hoge() {
std::cout << "hoge (" << i << "): Bye.\n";
}
void foo() {
std::cout << "hoge (" << i << "): Foo!\n";
}
int i;
};
void basic_usage()
{
{
// managed object
etude::scoped_ptr<hoge> p( new hoge(1) );
p->foo();
// is automatically deleted.
}
{
etude::scoped_ptr<hoge> p1( new hoge(2) );
// you can 'move ownership' to another pointer
etude::scoped_ptr<hoge> p2( p1.move() );
// moved pointer becomes empty
BOOST_ASSERT( !p1 && p2 );
// you can 'move ownership' by assigning
p1 = p2.move();
BOOST_ASSERT( p1 && !p2 );
// or swapping
swap( p1, p2 ); // or p1.swap(p2);
BOOST_ASSERT( !p1 && p2 );
// foo!
p2->foo();
// automatically deleted.
}
{
// managed object
etude::scoped_ptr<hoge> p( new hoge(3) );
// can be released.
hoge* const p_ = p.release();
BOOST_ASSERT( !p );
// do not forget deleting when you released.
delete p_;
}
}
// factory
etude::move_ptr<hoge> create_hoge( int i ) {
return etude::scoped( new hoge(i) ); // helper function
}
// deleter
struct file_closer
{
void operator()( std::FILE* file ) const {
std::fclose( file );
}
};
void advanced_usage()
{
{
// you can make factory-function, returns etude::move_ptr<T>
etude::scoped_ptr<hoge> p( create_hoge(4) );
// factory-function will free us from risk of memory-leak.
create_hoge(5);
// foo!
p->foo();
}
{
// scoped_ptr and move_ptr can store arrays.
etude::scoped_ptr<int[]> a( new int[6] );
// pointer to array provides operator[]
a[0] = 0;
// and operator+.
std::fill( a+1, a+6, 1 );
BOOST_ASSERT( a[1] == 1 );
// delete [] a.get() is called
}
{
// using custom-deleter
etude::scoped_ptr<std::FILE, file_closer> const f_( std::tmpfile() );
std::FILE* const f = f_.get(); // for simple access
// I/O
std::fprintf( f, "hogehoge" );
// and so on...
// automatically closed
}
}
int main()
{
basic_usage();
advanced_usage();
}
/*
scoped_ptr : boost::scoped_ptr のカスタム削除子指定可能版
機能:
要するに std::unique_ptr です。
C++0x の rvalue-reference には対応していないものの、 move_ptr と組み合わせることで、
擬似的に move-semantics を再現することが出来ます:
move_ptr<hoge> create_hoge() {
return move_ptr<hoge>( new hoge() );
}
scoped_ptr<hoge> p( create_hoge() );
scoped_ptr<hoge> p2( p.move() );
p2.reset();
p = create_hoge();
p2 = p.move();
*/
#ifndef ETUDE_INCLUDED_SCOPED_PTR_HPP_
#define ETUDE_INCLUDED_SCOPED_PTR_HPP_
#include <boost/noncopyable.hpp>
#include "move_ptr.hpp"
namespace etude {
template< class T, class Deleter = etude::default_delete<T> >
struct scoped_ptr
: pointer_facade< scoped_ptr<T, Deleter>, T, detail_::move_ptr_category >,
private boost::noncopyable
{
// basic types
typedef typename pointer_types<T>::pointer pointer;
typedef Deleter deleter;
typedef typename pointer_types<T>::element_type element_type;
typedef Deleter deleter_type;
// move type
typedef move_ptr<T, Deleter> move_type;
// construct/destory
// default-construct
scoped_ptr()
: impl_() {}
explicit scoped_ptr( deleter d )
: impl_( d ) {}
// from raw pointer
explicit scoped_ptr( pointer p )
: impl_( p ) {}
scoped_ptr( pointer p, deleter d )
: impl_( p, d ) {}
// destroy
~scoped_ptr() {}
// from move_ptr
template<class U, class D>
scoped_ptr( move_ptr<U, D> src )
: impl_( src ) {}
template<class U, class D>
scoped_ptr& operator=( move_ptr<U, D> src ) {
impl_ = src;
return *this;
}
// from std::auto_ptr
template<class U>
scoped_ptr( std::auto_ptr<U> src )
: impl_( src.release() ) {}
template<class U>
scoped_ptr( std::auto_ptr<U> src, Deleter d )
: impl_( src.release(), d ) {}
template<class U>
scoped_ptr& operator=( std::auto_ptr<U> rhs ) {
scoped_ptr(rhs).swap(*this);
return *this;
}
// modifiers
void swap( scoped_ptr& other ) {
impl_.swap( other.impl_ );
}
friend void swap( scoped_ptr& one, scoped_ptr& another ) {
one.swap( another );
}
void reset() {
scoped_ptr().swap(*this);
}
void reset( pointer p ) {
scoped_ptr(p).swap(*this);
}
void reset( pointer p, deleter d ) {
scoped_ptr( p, d ).swap(*this);
}
pointer release() {
return impl_.release();
}
// move content
move_type move() {
return impl_;
}
// observers
// pointer access
pointer get_pointer() const { return impl_.get_pointer(); }
// deleter access
deleter& get_deleter() { return impl_.get_deleter(); }
deleter const& get_deleter() const { return impl_.get_deleter(); }
// other observers are generated by pointer_facade
private:
move_ptr<T, Deleter> impl_;
};
} // namespace etude
#endif // #ifndef ETUDE_INCLUDED_SCOPED_PTR_HPP_
#include "scoped_ptr.hpp"
// object counter to detect leaks
template<class Tag>
struct instance_counter
{
instance_counter() {
++count_();
}
instance_counter( instance_counter const& ) {
++count_();
}
~instance_counter() {
--count_();
}
static int use_count() {
return count_();
}
private:
static int& count_() {
static int count = 0;
return count;
}
};
// contained object
struct hoge
: instance_counter<hoge>
{
using instance_counter<hoge>::use_count;
explicit hoge( int x_ = 0 )
: x( x_ ) {}
int x;
};
// factory
etude::move_ptr<hoge> create_hoge( int x = 0 ) {
return etude::scoped( new hoge(x) );
}
#include <boost/test/minimal.hpp>
void basic_test()
{
typedef etude::scoped_ptr<hoge> pointer;
// check count
int const count = hoge::use_count();
// default construction
pointer const p0;
BOOST_CHECK( !p0 );
BOOST_CHECK( p0.get() == 0 );
// from raw-pointer
{
pointer p1( new hoge(1) ), p2( 0 );
BOOST_CHECK( p1 != 0 && p2 == 0 );
BOOST_CHECK( p1 != p0 && p2 == p0 );
BOOST_CHECK( &*p1 == p1.get() && p2.get() == 0 );
BOOST_CHECK( p1->x == 1 );
// allocated object
BOOST_CHECK( hoge::use_count() == count + 1 );
// is automatically deleted.
}
BOOST_CHECK( hoge::use_count() == count );
// from move_type
{
pointer p1( create_hoge(0) );
hoge* const p = p1.get();
BOOST_CHECK( p1 != 0 );
BOOST_CHECK( p1->x == 0 );
BOOST_CHECK( hoge::use_count() == count + 1 );
p1 = create_hoge(1);
BOOST_CHECK( p1 != 0 );
BOOST_CHECK( p1.get() != p );
BOOST_CHECK( p1->x == 1 );
BOOST_CHECK( hoge::use_count() == count + 1 );
}
BOOST_CHECK( hoge::use_count() == count );
// reset
{
pointer p0, p1( new hoge(1) );
BOOST_CHECK( !p0 && p1 );
BOOST_CHECK( hoge::use_count() == count + 1 );
// p.reset() has no side-effect if p is empty.
p0.reset();
BOOST_CHECK( !p0 );
BOOST_CHECK( hoge::use_count() == count + 1 );
// reset empty pointer to raw-pointer
{
hoge* const p = new hoge(2);
p0.reset( p );
BOOST_CHECK( p0.get() == p );
}
BOOST_CHECK( hoge::use_count() == count + 2 );
// reset non-empty pointer to empty
p0.reset();
BOOST_CHECK( hoge::use_count() == count + 1 );
// reset non-empty pointer to raw-pointer
{
hoge* const p = new hoge(3);
p1.reset( p );
BOOST_CHECK( p1.get() == p );
}
BOOST_CHECK( hoge::use_count() == count + 1 );
}
BOOST_CHECK( hoge::use_count() == count );
// release
{
hoge* const p = new hoge(1);
{
pointer p0, p1( p );
BOOST_CHECK( hoge::use_count() == count + 1 );
// release() has no side-effect if pointer is empty.
BOOST_CHECK( p0.release() == 0 );
BOOST_CHECK( hoge::use_count() == count + 1 );
BOOST_CHECK( p1.release() == p );
BOOST_CHECK( p1 == 0 );
BOOST_CHECK( hoge::use_count() == count + 1 );
}
// not deleted
BOOST_CHECK( hoge::use_count() == count + 1 );
delete p;
}
BOOST_CHECK( hoge::use_count() == count );
// move
{
hoge* const p = new hoge(1);
pointer p1( p );
BOOST_CHECK( p1.get() == p );
// move construction
pointer p2( p1.move() );
BOOST_CHECK( !p1 && p2.get() == p );
// move
p1 = p2.move();
BOOST_CHECK( p1.get() == p && !p2 );
// move from empty pointer
p1 = p2.move();
BOOST_CHECK( !p1 && !p2 );
BOOST_CHECK( hoge::use_count() == count );
}
}
void array_test()
{
typedef etude::scoped_ptr<hoge[]> pointer;
int const count = hoge::use_count();
// 基本的なこと
{
int const n = 10;
hoge* const p = new hoge[n];
BOOST_CHECK( hoge::use_count() == count + n );
pointer p1( p );
BOOST_CHECK( p1.get() == p );
BOOST_CHECK( &p1[0] == p );
BOOST_CHECK( p1+1 == p+1 );
p1.reset();
BOOST_CHECK( !p1 );
BOOST_CHECK( hoge::use_count() == count );
}
// move とかも
{
int const n = 42;
hoge* const p = new hoge[n];
pointer p1( p );
BOOST_CHECK( p1.get() == p );
pointer::move_type mp( p1.move() );
BOOST_CHECK( mp.get() == p && !p1 );
p1 = mp;
BOOST_CHECK( p1.get() == p && !mp );
BOOST_CHECK( hoge::use_count() == count + n );
delete [] p1.release();
BOOST_CHECK( !p1 );
BOOST_CHECK( hoge::use_count() == count );
}
}
void deleter_test();
#include <boost/noncopyable.hpp>
#include <boost/assert.hpp>
struct intrusive_ptr_releaser
{
// no result_type, argument_type for test
template<class T>
void operator()( T* ptr ) // non-const, for test
{
BOOST_ASSERT( ptr != 0 );
using namespace boost;
intrusive_ptr_release( ptr );
}
};
struct fuga
: private instance_counter<fuga>, private boost::noncopyable
{
using instance_counter<fuga>::use_count;
typedef etude::scoped_ptr<fuga, intrusive_ptr_releaser> pointer;
typedef pointer::move_type move_type;
static move_type new_() {
return etude::scoped( new fuga, intrusive_ptr_releaser() );
}
friend void intrusive_ptr_add_ref( fuga const* p ) {
++p->ref_count_;
}
friend void intrusive_ptr_release( fuga const* p ) {
if( --p->ref_count_ == 0 ) {
delete p;
}
}
friend int intrusive_ptr_use_count( fuga const* p ) {
return p->ref_count_;
}
private:
mutable int ref_count_;
fuga() : ref_count_(1) {}
~fuga() {
BOOST_ASSERT( ref_count_ == 0 );
}
};
void deleter_test()
{
typedef fuga::pointer pointer;
int const count = fuga::use_count();
{
// constructor which takes deleter
intrusive_ptr_releaser d;
pointer p0( d );
assert( !p0 );
p0 = fuga::new_();
BOOST_CHECK( fuga::use_count() == count + 1 );
// reset which takes deleter
p0.reset( 0, d );
BOOST_CHECK( fuga::use_count() == count );
}
{
pointer p1( fuga::new_() );
// copying( by add-ref )
pointer p2( p1.get() );
intrusive_ptr_add_ref( p2.get() );
BOOST_CHECK( p1 == p2 );
BOOST_CHECK( intrusive_ptr_use_count( p1.get() ) == 2 );
// conversion between defferent pointer types
etude::scoped_ptr<fuga const, intrusive_ptr_releaser> p3( p2.move() );
BOOST_CHECK( p1 == p3 && !p2 );
BOOST_CHECK( intrusive_ptr_use_count( p1.get() ) == 2 );
// assignment between defferent pointer types
p3 = p2.move();
BOOST_CHECK( !p2 && !p3 );
BOOST_CHECK( intrusive_ptr_use_count( p1.get() ) == 1 );
BOOST_CHECK( fuga::use_count() == count + 1 );
}
BOOST_CHECK( fuga::use_count() == count );
}
int test_main( int, char** )
{
basic_test();
array_test();
deleter_test();
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment