Boost Python - C++ class' private static data blown away beforeaccessing in Python?

Discussion in 'Python' started by Stodge, Jul 4, 2008.

  1. Stodge

    Stodge Guest

    I've exposed a C++ class to Python using Boost Python. The class,
    let's say it's called Entity, contains private static data, which is
    an array of strings. Though I think it implements it using MFC's
    CPtrArray.

    I've also exposed a public function from Entity - let's say it's
    called foo. This function accesses the private static data (the string
    array).

    I have multiple instances of Entity stored in a custom C++ container,
    which is also exposed to Python as class EntityList.

    In Python, I retrive an Entity from the EntityList:

    elist = EntityList()
    elist.append(Entity())
    elist.append(Entity())

    entity = elist.get_at(0)

    entity.foo()

    But it crashes inside foo() as the private static data is empty; or
    rather the string array is empty. I know before that point that the
    private static data is valid when accessed earlier by the C++ code as
    the program works fine. It just won't work from Python, so somehow the
    private static data has been blown away but I can't work out where or
    why.

    The static data is setup at initialisation - my Python code is only
    called long after initialisation is complete.

    I added a static dump() function to the Entity class that dumps the
    string array, and even if I just do the following in Python:

    Entity.dump()

    in Python, the private static data is empty. Doing the same from C++
    works fine. Weird.

    I know this is an impossible question to ask, but can anyone think of
    something obvious I need to look into?

    Thanks
     
    Stodge, Jul 4, 2008
    #1
    1. Advertising

  2. >
    > In Python, I retrive an Entity from the EntityList:
    >
    > elist = EntityList()
    > elist.append(Entity())
    > elist.append(Entity())
    >
    > entity = elist.get_at(0)
    >
    > entity.foo()
    >
    > But it crashes inside foo() as the private static data is empty; or
    > rather the string array is empty. I know before that point that the
    > private static data is valid when accessed earlier by the C++ code as
    > the program works fine. It just won't work from Python, so somehow the
    > private static data has been blown away but I can't work out where or
    > why.


    Probably it is a problem of lifetime. What is the signature of append?
    Who deletes the appended Entity in C++ code?
    If append takes a raw pointer, Boost.Python copies the pointer but
    destroys the Entity object because it is a temporary and its reference
    count went to zero. So the pointer in the list is referring to a
    destroyed object, which results in undefined behaviour.

    Did you have a look at the lifetime policies of Boost.Python? The
    simplest way to workaround the problem is using const reference
    arguments, and always use value semantics. If it can result in a
    performance penalty, another simple way is using shared_ptr's, which
    have their own reference count (different from the one in CPython
    lib), but Boost.Python does the magic to make them work together.

    HTH,
    Giuseppe
     
    Giuseppe Ottaviano, Jul 6, 2008
    #2
    1. Advertising

  3. Stodge

    Stodge Guest

    Thanks. Maybe it's a DLL boundary issue? I'll look into this too.

    On Jul 5, 11:14 pm, Giuseppe Ottaviano <> wrote:
    > > In Python, I retrive an Entity from the EntityList:

    >
    > > elist = EntityList()
    > > elist.append(Entity())
    > > elist.append(Entity())

    >
    > > entity = elist.get_at(0)

    >
    > > entity.foo()

    >
    > > But it crashes inside foo() as the private static data is empty; or
    > > rather the string array is empty. I know before that point that the
    > > private static data is valid when accessed earlier by the C++ code as
    > > the program works fine. It just won't work from Python, so somehow the
    > > private static data has been blown away but I can't work out where or
    > > why.

    >
    > Probably it is a problem of lifetime. What is the signature of append?  
    > Who deletes the appended Entity in C++ code?
    > If append takes a raw pointer, Boost.Python copies the pointer but  
    > destroys the Entity object because it is a temporary and its reference  
    > count went to zero. So the pointer in the list is referring to a  
    > destroyed object, which results in undefined behaviour.
    >
    > Did you have a look at the lifetime policies of Boost.Python? The  
    > simplest way to workaround the problem is using const reference  
    > arguments, and always use value semantics. If it can result in a  
    > performance penalty, another simple way is using shared_ptr's, which  
    > have their own reference count (different from the one in CPython  
    > lib), but Boost.Python does the magic to make them work together.
    >
    > HTH,
    > Giuseppe
     
    Stodge, Jul 9, 2008
    #3
  4. Stodge

    Stodge Guest

    I wonder if it's a DLL boundary problem.

    On Jul 5, 11:14 pm, Giuseppe Ottaviano <> wrote:
    > > In Python, I retrive an Entity from the EntityList:

    >
    > > elist = EntityList()
    > > elist.append(Entity())
    > > elist.append(Entity())

    >
    > > entity = elist.get_at(0)

    >
    > > entity.foo()

    >
    > > But it crashes inside foo() as the private static data is empty; or
    > > rather the string array is empty. I know before that point that the
    > > private static data is valid when accessed earlier by the C++ code as
    > > the program works fine. It just won't work from Python, so somehow the
    > > private static data has been blown away but I can't work out where or
    > > why.

    >
    > Probably it is a problem of lifetime. What is the signature of append?  
    > Who deletes the appended Entity in C++ code?
    > If append takes a raw pointer, Boost.Python copies the pointer but  
    > destroys the Entity object because it is a temporary and its reference  
    > count went to zero. So the pointer in the list is referring to a  
    > destroyed object, which results in undefined behaviour.
    >
    > Did you have a look at the lifetime policies of Boost.Python? The  
    > simplest way to workaround the problem is using const reference  
    > arguments, and always use value semantics. If it can result in a  
    > performance penalty, another simple way is using shared_ptr's, which  
    > have their own reference count (different from the one in CPython  
    > lib), but Boost.Python does the magic to make them work together.
    >
    > HTH,
    > Giuseppe
     
    Stodge, Jul 9, 2008
    #4
  5. Stodge

    Stodge Guest

    Could it be a boundary problem? The static data is initialised by the
    application. The problem arises when the python module tries to access
    it.

    On Jul 5, 11:14 pm, Giuseppe Ottaviano <> wrote:
    > > In Python, I retrive an Entity from the EntityList:

    >
    > > elist = EntityList()
    > > elist.append(Entity())
    > > elist.append(Entity())

    >
    > > entity = elist.get_at(0)

    >
    > > entity.foo()

    >
    > > But it crashes inside foo() as the private static data is empty; or
    > > rather the string array is empty. I know before that point that the
    > > private static data is valid when accessed earlier by the C++ code as
    > > the program works fine. It just won't work from Python, so somehow the
    > > private static data has been blown away but I can't work out where or
    > > why.

    >
    > Probably it is a problem of lifetime. What is the signature of append?  
    > Who deletes the appended Entity in C++ code?
    > If append takes a raw pointer, Boost.Python copies the pointer but  
    > destroys the Entity object because it is a temporary and its reference  
    > count went to zero. So the pointer in the list is referring to a  
    > destroyed object, which results in undefined behaviour.
    >
    > Did you have a look at the lifetime policies of Boost.Python? The  
    > simplest way to workaround the problem is using const reference  
    > arguments, and always use value semantics. If it can result in a  
    > performance penalty, another simple way is using shared_ptr's, which  
    > have their own reference count (different from the one in CPython  
    > lib), but Boost.Python does the magic to make them work together.
    >
    > HTH,
    > Giuseppe
     
    Stodge, Jul 9, 2008
    #5
  6. Stodge

    Stodge Guest

    Oops - I didn't see my post so I thought something had gone wrong and
    reposted. Apologies for the multiple posts.

    On Jul 9, 11:57 am, Stodge <> wrote:
    > Could it be a boundary problem? The static data is initialised by the
    > application. The problem arises when the python module tries to access
    > it.
    >
    > On Jul 5, 11:14 pm, Giuseppe Ottaviano <> wrote:
    >
    > > > In Python, I retrive an Entity from the EntityList:

    >
    > > > elist = EntityList()
    > > > elist.append(Entity())
    > > > elist.append(Entity())

    >
    > > > entity = elist.get_at(0)

    >
    > > > entity.foo()

    >
    > > > But it crashes inside foo() as the private static data is empty; or
    > > > rather the string array is empty. I know before that point that the
    > > > private static data is valid when accessed earlier by the C++ code as
    > > > the program works fine. It just won't work from Python, so somehow the
    > > > private static data has been blown away but I can't work out where or
    > > > why.

    >
    > > Probably it is a problem of lifetime. What is the signature of append?  
    > > Who deletes the appended Entity in C++ code?
    > > If append takes a raw pointer, Boost.Python copies the pointer but  
    > > destroys the Entity object because it is a temporary and its reference  
    > > count went to zero. So the pointer in the list is referring to a  
    > > destroyed object, which results in undefined behaviour.

    >
    > > Did you have a look at the lifetime policies of Boost.Python? The  
    > > simplest way to workaround the problem is using const reference  
    > > arguments, and always use value semantics. If it can result in a  
    > > performance penalty, another simple way is using shared_ptr's, which  
    > > have their own reference count (different from the one in CPython  
    > > lib), but Boost.Python does the magic to make them work together.

    >
    > > HTH,
    > > Giuseppe
     
    Stodge, Jul 9, 2008
    #6
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. DaveLessnau
    Replies:
    3
    Views:
    448
    Howard
    May 16, 2005
  2. G Patel
    Replies:
    2
    Views:
    426
    Lawrence Kirby
    Jan 24, 2005
  3. Robin
    Replies:
    0
    Views:
    439
    Robin
    Jun 6, 2007
  4. joes
    Replies:
    3
    Views:
    330
  5. Hicham Mouline
    Replies:
    5
    Views:
    2,455
    James Kanze
    Dec 19, 2008
Loading...

Share This Page