如果A
是一个拥有 实例的容器Type
,那么考虑A::iterator
包含一个句柄Type
而不是一个Type
:
class iterator {
[...]
private:
Type* instance; // has a handle to a Type instance.
};
代替:
class iterator {
[...]
private:
Type instance; // has a Type instance.
};
在 python 中,迭代器将包含对其迭代的容器的引用。这将延长可迭代对象的生命周期,并防止可迭代对象在迭代期间被垃圾回收。
>>> from sys import getrefcount
>>> x = [1,2,3]
>>> getrefcount(x)
2 # One for 'x' and one for the argument within the getrefcount function.
>>> iter = x.__iter__()
>>> getrefcount(x)
3 # One more, as iter contains a reference to 'x'.
boost::python
支持这种行为。这是一个示例程序,它Foo
是一个无法复制的简单类型;FooContainer
作为一个可迭代的容器;FooContainer::iterator
作为一个迭代器:
#include <boost/python.hpp>
#include <iterator>
// Simple example type.
class Foo
{
public:
Foo() { std::cout << "Foo constructed: " << this << std::endl; }
~Foo() { std::cout << "Foo destroyed: " << this << std::endl; }
void set_x( int x ) { x_ = x; }
int get_x() { return x_; }
private:
Foo( const Foo& ); // Prevent copy.
Foo& operator=( const Foo& ); // Prevent assignment.
private:
int x_;
};
// Container for Foo objects.
class FooContainer
{
private:
enum { ARRAY_SIZE = 3 };
public:
// Default constructor.
FooContainer()
{
std::cout << "FooContainer constructed: " << this << std::endl;
for ( int i = 0; i < ARRAY_SIZE; ++i )
{
foos_[ i ].set_x( ( i + 1 ) * 10 );
}
}
~FooContainer()
{
std::cout << "FooContainer destroyed: " << this << std::endl;
}
// Iterator for Foo types.
class iterator
: public std::iterator< std::forward_iterator_tag, Foo >
{
public:
// Constructors.
iterator() : foo_( 0 ) {} // Default (empty).
iterator( const iterator& rhs ) : foo_( rhs.foo_ ) {} // Copy.
explicit iterator(Foo* foo) : foo_( foo ) {} // With position.
// Dereference.
Foo& operator*() { return *foo_; }
// Pre-increment
iterator& operator++() { ++foo_; return *this; }
// Post-increment.
iterator operator++( int )
{
iterator tmp( foo_ );
operator++();
return tmp;
}
// Comparison.
bool operator==( const iterator& rhs ) { return foo_ == rhs.foo_; }
bool operator!=( const iterator& rhs )
{
return !this->operator==( rhs );
}
private:
Foo* foo_; // Contain a handle to foo; FooContainer owns Foo.
};
// begin() and end() are requirements for the boost::python's
// iterator< container > spec.
iterator begin() { return iterator( foos_ ); }
iterator end() { return iterator( foos_ + ARRAY_SIZE ); }
private:
FooContainer( const FooContainer& ); // Prevent copy.
FooContainer& operator=( const FooContainer& ); // Prevent assignment.
private:
Foo foos_[ ARRAY_SIZE ];
};
BOOST_PYTHON_MODULE(iterator_example)
{
using namespace boost::python;
class_< Foo, boost::noncopyable >( "Foo" )
.def( "get_x", &Foo::get_x )
;
class_< FooContainer, boost::noncopyable >( "FooContainer" )
.def("__iter__", iterator< FooContainer, return_internal_reference<> >())
;
}
这是示例输出:
>>> from iterator_example import FooContainer
>>> fc = FooContainer()
Foo constructed: 0x8a78f88
Foo constructed: 0x8a78f8c
Foo constructed: 0x8a78f90
FooContainer constructed: 0x8a78f88
>>> for foo in fc:
... print foo.get_x()
...
10
20
30
>>> fc = foo = None
FooContainer destroyed: 0x8a78f88
Foo destroyed: 0x8a78f90
Foo destroyed: 0x8a78f8c
Foo destroyed: 0x8a78f88
>>>
>>> fc = FooContainer()
Foo constructed: 0x8a7ab48
Foo constructed: 0x8a7ab4c
Foo constructed: 0x8a7ab50
FooContainer constructed: 0x8a7ab48
>>> iter = fc.__iter__()
>>> fc = None
>>> iter.next().get_x()
10
>>> iter.next().get_x()
20
>>> iter = None
FooContainer destroyed: 0x8a7ab48
Foo destroyed: 0x8a7ab50
Foo destroyed: 0x8a7ab4c
Foo destroyed: 0x8a7ab48