简体   繁体   English

Boost.Python中的C ++静态

[英]C++ statics in Boost.Python

I have a C++ class which contains some kind of "static state" ("m_engine" in this particular case): 我有一个C ++类,它包含某种“静态”(在这种特殊情况下为“m_engine”):

class RndGenerator
{
public:
  static void setInitialSeed(unsigned int seed);
  static unsigned int rndNumber();
  ...
private:
  ...
  RndGenerator();
  static std::mt19937 m_engine;
};

This class is used extensively in my project, on C++ level. 这个类在我的项目中广泛使用,在C ++级别。

After exposing RndGenerator via Boost.Python: 通过Boost.Python公开RndGenerator之后:

class_<RndGenerator, boost::noncopyable>("RndGenerator", no_init)
  .def("setInitialSeed", &RndGenerator::setInitialSeed)
  .staticmethod("setInitialSeed")
  .def("rndNumber", &RndGenerator::rndNumber)
  .staticmethod("rndNumber")
  ;

I would like to have possibility to set initial seed from Python level: 我想有可能从Python级别设置初始种子:

 RndGenerator.setInitialSeed(1234)

I would expect, that after this line all calls to RndGenerator::rndNumber(), on C++ level, would take into account just specified initial seed (1234). 我希望,在这一行之后,在C ++级别上所有对RndGenerator :: rndNumber()的调用都会考虑到指定的初始种子(1234)。 However this is not the case. 然而,这种情况并非如此。

Is there any problem with classes containing static members exposed to Python? 包含暴露给Python的静态成员的类是否有任何问题? Or is my problem related to singleton-like nature of RndGenerator? 或者我的问题与RndGenerator的类似单身的性质有关吗?

There should be no problems with Boost.Python using static data members or static member functions on C++ classes being exposed. Boost.Python在暴露的C ++类上使用静态数据成员或静态成员函数应该没有问题。 Is it possible that this is a false-positive? 这可能是假阳性吗? Alternatively, for more complex and specific cases where the same template is instantiated in multiple translation units, then with dynamic libraries, multiple instances of static data members with the same symbolic name may reside within the same process space. 或者,对于在多个转换单元中实例化相同模板的更复杂和特定情况,然后使用动态库,具有相同符号名称的多个静态数据成员实例可以驻留在同一进程空间内。

Regardless, here is a complete example demonstrating the expected behavior of static member functions and static data members on a class exposed with Boost.Python: 无论如何,这是一个完整的示例,演示静态成员函数和静态数据成员在使用Boost.Python公开的类上的预期行为:

#include <boost/python.hpp>

// Basic mockup type.
class spam
{
public:
  static void set_x(unsigned int x) { x_ = x; }
  static unsigned int get_x() { return x_; };
private:
  spam() {};
  spam(const spam&);
  spam& operator=(const spam&);
  static unsigned int x_;
};

unsigned int spam::x_ = 0;

// Auxiliary function.
bool spam_check_x(unsigned int x)
{
  return x == spam::get_x();
}

BOOST_PYTHON_MODULE(example)
{
  namespace python = boost::python;
  python::class_<spam, boost::noncopyable>("Spam", python::no_init)
    .def("setX", &spam::set_x)
      .staticmethod("setX")
    .def("getX", &spam::get_x)
      .staticmethod("getX")
    .def("checkX", &spam_check_x)
      .staticmethod("checkX")
    ;
}

Interactive usage: 互动用法:

>>> from example import Spam
>>> x = 42
>>> assert(Spam.getX() != x)
>>> assert(not Spam.checkX(x))
>>> Spam.setX(x)
>>> assert(Spam.getX() == x)
>>> assert(Spam.checkX(x))
>>> x = 43
>>> assert(Spam.getX() != x)
>>> assert(not Spam.checkX(x))

I realize this is an old question, but I ran into this same issue recently and figured I should share. 我意识到这是一个老问题,但我最近遇到了同样的问题,并认为我应该分享。

We were able to reproduce the issue on Windows with Boost 1.56 with the following steps: 我们能够使用Boost 1.56在Windows上重现该问题,步骤如下:

  • In C++, create two separate Boost.Python modules: 在C ++中,创建两个单独的Boost.Python模块:
    • Module A exposes a function to set a static variable in class Foo 模块A公开一个函数来设置类Foo中的静态变量
    • Module B exposes a function to access Foo's static variable 模块B公开了一个访问Foo静态变量的函数
  • In Python, call A's setter followed by B's getter. 在Python中,调用A的setter,然后调用B的getter。 You would expect the value to match, but (at least in our case) B's static will still be set to its default value. 您希望该值匹配,但(至少在我们的情况下)B的静态仍将设置为其默认值。

This only breaks across the extension module boundary (separate .pyd files). 这只会突破扩展模块边界(单独的.pyd文件)。 The issue has to do with dynamic linkage behavior on Windows. 该问题与Windows上的动态链接行为有关。 Here is a wiki page that discusses a different manifestation of the same issue. 是一个维基页面,讨论了同一问题的不同表现形式。

Our solution was to merge the C++ modules into a single Boost.Python module, and therefore a single shared object. 我们的解决方案是将C ++模块合并到一个Boost.Python模块中,因此也就是一个共享对象。 To mimic our old setup, we added submodules to maintain the separation between libraries: 为了模仿我们的旧设置,我们添加了子模块来维护库之间的分离:

// Put all following definitions in the current scope into a namespace-esque module
#define MAKE_MODULE(modName) \
    boost::python::object module(boost::python::handle<>(boost::python::borrowed(PyImport_AddModule("pymod."#modName)))); \
    scope().attr(#modName) = module; \
    scope s(module);

using namespace boost::python;

BOOST_PYTHON_MODULE(pymod)
{
    object package = scope();
    package.attr("__path__") = "pymod";

    // pymod.a
    {
        MAKE_MODULE(a);
        exportModuleA();
    }

    // pymod.b
    {
        MAKE_MODULE(b);
        exportModuleB();
    }

    ...
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM