【问题标题】:SWIG: How to wrap boost::shared_ptr to std::vector?SWIG:如何将 boost::shared_ptr 包装到 std::vector?
【发布时间】:2026-01-29 15:45:01
【问题描述】:

我有一些 C++ 代码将 boost::shared_ptr 返回到 std::vector,但是我无法让 SWIG 正确包装它以使对象在 Python 中可迭代。没有 boost::shared_ptr 它工作正常。有谁知道当向量在 shared_ptr 中时如何包装它?

这是一个演示问题的示例:

%module example

%include <std_vector.i>
%include <boost_shared_ptr.i>

%shared_ptr(Inner)
%shared_ptr(InnerVector)

%inline %{
#include <boost/shared_ptr.hpp>
#include <vector>

struct Inner {
  int dummy;
};
typedef std::vector< boost::shared_ptr<Inner> > InnerVector;
typedef boost::shared_ptr<InnerVector> InnerVectorPtr;

InnerVectorPtr getVectorPtr()
{
  InnerVectorPtr v(new InnerVector());
  boost::shared_ptr<Inner> i(new Inner);
  i->dummy = 222;
  v->push_back(i);
  return v;
}

%}

%template(InnerVector) ::std::vector< boost::shared_ptr<Inner> >;

还有一个 Python 脚本示例:

import example

v = example.getVectorPtr()
print 'Vector is:', v
for i in v:
     print 'Instance is:', i
     print 'Value is:', i.dummy

这对我来说是这样说的:

Vector is: <Swig Object of type 'InnerVectorPtr *' at 0x1127270>
Traceback (most recent call last):
  File "test.py", line 5, in <module>
    for i in v:
TypeError: 'SwigPyObject' object is not iterable

有什么建议吗?

【问题讨论】:

  • 为什么要返回指向向量的共享指针?
  • 因为向量可以有大量条目,我想避免它在返回时被复制,因为该函数会被频繁调用。我可以改为返回对向量的引用(尽管 SWIG 不喜欢那样),但这意味着调用者必须更加小心。但如果你有更好的建议,我会全力以赴。
  • 如果您还没有进行分析以表明复制该向量是一个问题,我不会担心它并复制您想要的所有内容。
  • 这是一个公平的观点,但我很确定分析在这里不会带来任何惊喜 - 向量包含大约 1000 个要在屏幕上每秒绘制多次的项目,所以如果我删除共享指针我无疑必须重构代码以缓存向量,以免帧速率受到影响...编辑:另外,我讨厌仅仅因为 Python 包装器不符合要求而不得不更改我的精细 C++ 代码;- )

标签: c++ python swig


【解决方案1】:

您可能想试试Boost.PythonPy++。如果您已经在使用 Boost,它会为复杂的 C++ 结构提供非常好的包装(并且几乎是自动包装)。我已经在几个项目中使用过它。

您还应该查看this question,它看起来相关但不完全是您的问题。

【讨论】:

  • 感谢您的指点 - 是的,我已经看到了这个问题,但我确实有这部分工作 - 只有在添加另一层共享指针时它才会失败。我最初避开了 Boost.Python,因为看起来我必须掌握 bjam 才能让它工作。你知道是否可以在 Linux 机器上使用 bjam 交叉编译绑定以在 Windows 下的 Python 解释器上运行?
  • 您当然不必使用 bjam 来使用 Boost.Python。这里根本没有魔法,你只需要为链接器/编译器提供正确的标志,这样他们就可以找到正确的 Boost.Python 和 libPython 版本(正确的是你构建 Boost.Python 的版本)。我假设如果您为 Windows 设置了正确的 C++ 和 C 交叉编译系统,那么您也应该能够制作包装器。您只需要为 Windows 编译的 Boost.Python 和 libPython 版本。
【解决方案2】:

你的问题解决了吗?

我在想这可能是名称管理的问题,因为您两次使用相同的名称InnerVector

%template(InnerVector) ::std::vector&lt; boost::shared_ptr&lt;Inner&gt; &gt;;

typedef std::vector&lt; boost::shared_ptr&lt;Inner&gt; &gt; InnerVector;

错误TypeError: 'SwigPyObject' object is not iterable 通常意味着 SWIG 不理解该对象是例如vector 并应转换为 Python 列表。

【讨论】:

  • 不幸的是我放弃了,只是删除了我的代码的 Python 接口。您的建议在我上面的示例代码中有效吗?我已经重新安装并且没有 SWIG 可以测试了!
  • 我尝试运行上面的示例,并得到同样的问题。显然,SWIG 可以处理名称修改问题。但是,您不能直接在 Python 中使用“shared_ptr”。您可能想看看this thread 以了解一般的向量包装。我在 Python 中使用了 boost::shared_ptr 对象,但仅作为不同 SWIG 包装的 C++ 函数之间的桥接数据容器。