SWIG、Boost 共享指针和继承

发布于 2024-10-12 05:18:50 字数 2667 浏览 3 评论 0原文

我在使用 SWIG、共享指针和继承时遇到问题。

我正在创建各种相互继承的 C++ 类,使用 Boost 共享指针来引用它们,然后包装这些共享指针 使用 SWIG 来创建 python 类的指针。

我的问题如下:

  • B 是 A 的子类
  • sA 是指向 A 的共享指针
  • sB 是指向 B 的共享指针
  • f(sA) 是一个需要指向 A 的共享指针的函数

  • 如果我将 sB 传递给 f(),则会引发错误。

  • 此错误仅发生在 python 级别。
  • 在 C++ 级别,我可以毫无问题地将 sB 传递给 f()。

我有 boost 1.40 和 swig 1.3.40。

以下是重现问题的 5 个文件的内容 与:

python setup.py build_ext --inplace
python test.py

swig_shared_ptr.h

#ifndef INCLUDED_SWIG_SHARED_PTR_H
#define INCLUDED_SWIG_SHARED_PTR_H

#include <boost/shared_ptr.hpp>

class Base {};

class Derived : public Base {};

typedef boost::shared_ptr<Base> base_sptr;
typedef boost::shared_ptr<Derived> derived_sptr;

void do_something (base_sptr bs);

base_sptr make_base();
derived_sptr make_derived();

#endif

swig_shared_ptr.cc

#include <iostream>
#include "swig_shared_ptr.h"

void do_something (base_sptr bs)
{
  std::cout << "Doing something." << std::endl;
}

base_sptr make_base() { return base_sptr(new Base ()); };
derived_sptr make_derived() { return derived_sptr(new Derived ()); };

swig_shared_ptr.i

%module(docstring="
Example module showing problems I am having with SWIG, shared pointers
and inheritance.
") swig_shared_ptr

%{
#include "swig_shared_ptr.h"
%}

%include <swig_shared_ptr.h>
%include <boost_shared_ptr.i>
%template(base_sptr) boost::shared_ptr<Base>;
%template(derived_sptr) boost::shared_ptr<Derived>;

setup.py

"""
setup.py file for swig_shared_ptr
"""

from distutils.core import setup, Extension

swig_shared_ptr_module = Extension('_swig_shared_ptr',
                         include_dirs = ['/usr/include/boost'],
                         sources=['swig_shared_ptr.i', 'swig_shared_ptr.cc'],
                         )

setup (name = 'swig_shared_ptr',
       version = '0.1',
       author = "Ben",
       description = """Example showing problems I am having with SWIG, shared
                        pointers and inheritance.""",
       ext_modules = [swig_shared_ptr_module],
       py_modules = ["swig_shared_ptr"],
       )

test.py

import swig_shared_ptr as ssp

bs = ssp.make_base()
dr = ssp.make_derived()

# Works fine.
ssp.do_something(bs) 
# Fails with "TypeError: in method 'do_something', argument 1 of type 'base_sptr'"
ssp.do_something(dr) 

I'm having trouble with SWIG, shared pointers, and inheritance.

I am creating various c++ classes which inherit from one another, using
Boost shared pointers to refer to them, and then wrapping these shared
pointers with SWIG to create the python classes.

My problem is the following:

  • B is a subclass of A
  • sA is a shared pointer to A
  • sB is a shared pointer to B
  • f(sA) is a function expecting a shared pointer to A

  • If I pass sB to f() then an error is raised.

  • This error only occurs at the python level.
  • At the C++ level I can pass sB to f() without a problem.

I have boost 1.40 and swig 1.3.40.

Below are the contents of 5 files which will reproduce the problem
with:

python setup.py build_ext --inplace
python test.py

swig_shared_ptr.h

#ifndef INCLUDED_SWIG_SHARED_PTR_H
#define INCLUDED_SWIG_SHARED_PTR_H

#include <boost/shared_ptr.hpp>

class Base {};

class Derived : public Base {};

typedef boost::shared_ptr<Base> base_sptr;
typedef boost::shared_ptr<Derived> derived_sptr;

void do_something (base_sptr bs);

base_sptr make_base();
derived_sptr make_derived();

#endif

swig_shared_ptr.cc

#include <iostream>
#include "swig_shared_ptr.h"

void do_something (base_sptr bs)
{
  std::cout << "Doing something." << std::endl;
}

base_sptr make_base() { return base_sptr(new Base ()); };
derived_sptr make_derived() { return derived_sptr(new Derived ()); };

swig_shared_ptr.i

%module(docstring="
Example module showing problems I am having with SWIG, shared pointers
and inheritance.
") swig_shared_ptr

%{
#include "swig_shared_ptr.h"
%}

%include <swig_shared_ptr.h>
%include <boost_shared_ptr.i>
%template(base_sptr) boost::shared_ptr<Base>;
%template(derived_sptr) boost::shared_ptr<Derived>;

setup.py

"""
setup.py file for swig_shared_ptr
"""

from distutils.core import setup, Extension

swig_shared_ptr_module = Extension('_swig_shared_ptr',
                         include_dirs = ['/usr/include/boost'],
                         sources=['swig_shared_ptr.i', 'swig_shared_ptr.cc'],
                         )

setup (name = 'swig_shared_ptr',
       version = '0.1',
       author = "Ben",
       description = """Example showing problems I am having with SWIG, shared
                        pointers and inheritance.""",
       ext_modules = [swig_shared_ptr_module],
       py_modules = ["swig_shared_ptr"],
       )

test.py

import swig_shared_ptr as ssp

bs = ssp.make_base()
dr = ssp.make_derived()

# Works fine.
ssp.do_something(bs) 
# Fails with "TypeError: in method 'do_something', argument 1 of type 'base_sptr'"
ssp.do_something(dr) 

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

不知在何时 2024-10-19 05:18:50

以下更改似乎可以解决该问题。

swig_shared_ptr.i 中,两行:

%template(base_sptr) boost::shared_ptr<Base>;
%template(derived_sptr) boost::shared_ptr<Derived>;

被移动,以便它们位于该行上方

%include <swig_shared_ptr.h>

,然后(在 SWIG 1.3 中)替换为:

SWIG_SHARED_PTR(Base, Base)
SWIG_SHARED_PTR_DERIVED(Derived, Base, Derived)    

或(在 SWIG 2.0 中)替换为:

%shared_ptr(Base)
%shared_ptr(Derived)

The following change appears to solve the problem.

In swig_shared_ptr.i the two lines:

%template(base_sptr) boost::shared_ptr<Base>;
%template(derived_sptr) boost::shared_ptr<Derived>;

are moved so that they are above the line

%include <swig_shared_ptr.h>

and are then replaced (in SWIG 1.3) by:

SWIG_SHARED_PTR(Base, Base)
SWIG_SHARED_PTR_DERIVED(Derived, Base, Derived)    

or (in SWIG 2.0) by:

%shared_ptr(Base)
%shared_ptr(Derived)
护你周全 2024-10-19 05:18:50

SWIG 对 boost::shared_ptr 类一无所知。因此,它无法判断 衍生_sptr 可以“转换”(我相信,这是通过一些疯狂的构造函数和模板元编程实现的)到 衍生_sptr。由于 SWIG 需要相当简单的类定义(或使用 %include 包含简单文件),因此您将无法准确声明 shared_ptr 类,因为 Boost 是 难以置信其编译器补偿和模板技巧并不简单。

至于解决方案:是否绝对有必要分发共享指针? SWIG 的 C++ 包装器基本上充当共享指针。 Boost 和 SWIG 很难协同工作。

SWIG doesn't know anything about the boost::shared_ptr<T> class. It therefore can't tell that derived_sptr can be "cast" (which is, I believe, implemented with some crazy constructors and template metaprogramming) to derived_sptr. Because SWIG requires fairly simple class definitions (or inclusion of simple files with %include), you won't be able to accurately declare the shared_ptr class, because Boost is incredibly non-simple with its compiler compensation and template tricks.

As to a solution: is it absolutely necessary to hand out shared pointers? SWIG's C++ wrappers basically function as shared pointers. Boost and SWIG are very, very difficult to get to work together.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文