문제

Short version

I don't understand how to reliably initialize static members for a python extension. In particular, how can I ensure a particular load order for code from different compilation units, so that certain dependencies are satisfied?

Long version

I have some code that computes various combinatoric functions many times, like the factorial, binomial, etc. It's much more efficient to just construct a table for these things once, and then do the lookup on them. And I need a nice interface for getting the values, so I just make c++ classes, with the tables as static members.

As the simplest example, to compute factorials, I have the following. In Combinatorics.hpp:

  class FactorialFunctor {
  private:
    static const std::vector<double> FactorialTable;
  public:
    FactorialFunctor() { };
    inline double operator()(const unsigned int i) const {
      return FactorialTable[i];
    }
  };

In Combinatorics.cpp:

const std::vector<double> FactorialFunctor::FactorialTable = FactorialTableCalculator();

where FactorialTableCalculator is a local function that just returns the appropriate vector. [Those operator()s get more complicated for binomials, etc., which is why I use classes to wrap these things.]

I use SWIG to wrap the c++ code up, and use it from python. This was all going well until I compiled my code on a new cluster that I'm using. Now I think I was just getting lucky previously.

As soon as I imported my python module on the new cluster, python would segfault. Python didn't even get back from the import step. Using gdb, I tracked this down to another part of the code, whose initialization calls a Factorial functor. But the FactorialTable hadn't been initialized yet, so the whole thing croaked.

So I need to ensure that my factorial is calculated before that other code is calculated. I tell distutils about it in the desired order, but obviously this isn't the order they get called on this cluster. Is there some stage in the linking process that I need to be careful with or something?

If you're really motivated, you can browse the code here and here, and the line that gives the segfault here.

도움이 되었습니까?

해결책

There is no reliable way to force the order your static members are initialized.

Looking at the code however I think that the thing you need is not a static member rather than a singleton. Singletons in C++ are usually implemented using functions like so:

FactorialFunctorData& _FactorialFunctorData()
{
    static FactorialFunctorData data_;
    return data_;
}

This way you may force the order on the execution time (by calling functions in the order needed).

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top