Domanda

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.

È stato utile?

Soluzione

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).

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top