gpt4 book ai didi

c++ - 如何将 boost::python::iterator 与 return_internal_reference 一起使用?

转载 作者:太空狗 更新时间:2023-10-29 21:48:13 26 4
gpt4 key购买 nike

我有一个类Type它不能被复制,也不包含默认构造函数。我有二等舱A充当上述类的集合。第二个类通过迭代器提供访问,我的迭代器有解引用运算符:

class A {
class iterator {
[...]
public:
Type & operator*()
{
return instance;
}
private:
Type instance;
}
[...]
};

现在揭露我写了一个boost::python看起来像这样的代码:

class_<A>("A", [...])
.def("__iter__", iterator<A, return_internal_reference<> >())
.def("__len__", container_length_no_diff<A, A::iterator>)
;

在为代码 Python 的所有迭代器操作(构造、赋值、取消引用、销毁)添加打印消息之后:

for o in AInstance:
print o.key

我得到输出(修剪到重要部分):

construct 0xffffffff7fffd3e8
dereference: 0xffffffff7fffd3e8
destroy 0xffffffff7fffd3e8
get key 0xffffffff7fffd3e8

在上面的代码中,这些地址只是 instance 的地址成员(或方法调用中的 this)。前三行由 iterator 生成,第四行是在Type中通过getter方法打印出来的.所以不知何故 boost::python以这样的方式包装一切:

  1. 创建迭代器
  2. 解引用迭代器并存储引用
  3. 销毁迭代器(及其包含的对象)
  4. 使用在第二步中获得的引用

这么清楚return_internal_reference并不像声明的那样(请注意,它实际上只是 with_custodian_and_ward_postcall<> 上的 typedef)只要引用了方法调用的结果,它就应该保留对象。

所以我的问题是如何使用 boost::python 将这样的迭代器暴露给 Python ?

编辑:

正如所指出的那样,它可能不清楚:原始容器不包含 Type 类型的对象。 .它包含一些 BaseType我能够从中构造/修改的对象 Type目的。所以iterator在上面的例子中就像transform_iterator .

最佳答案

如果 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

关于c++ - 如何将 boost::python::iterator 与 return_internal_reference 一起使用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11293270/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com