Created
November 24, 2010 14:00
-
-
Save gintenlabo/713685 to your computer and use it in GitHub Desktop.
カスタム削除子を指定可能 && 所有するポインタを release 出来る、俺々 scoped_ptr
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
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_ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
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_ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
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_ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
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_ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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(); | |
} | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
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_ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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