A RetroSearch Logo

Home - News ( United States | United Kingdom | Italy | Germany ) - Football scores

Search Query:

Showing content from https://github.com/pybind/pybind11/issues/5623 below:

smart_holder` · Issue #5623 · pybind/pybind11 · GitHub

Required prerequisites What version (or hash if on master) of pybind11 are you using?

bc4a66d

Problem description

I have a C++ base class that I bind using the trampoline class setup and py::smart_holder. I extend the base class with a derived Python class. I also have a C++ class (and bound Python class) that holds a std::weak_ptr<base>. If I give the holder class a pointer to an instance of the derived Python class, passed with std::shared_ptr<base>, when I later check on the status of the weak pointer, I find that it's expired.

I've verified this on the latest commit to the master branch (bc4a66d) using both a Mac and running in a Linux container on the Mac. Please see PR #5624 and the code in this issue for buildable examples demonstrating the problem.

With the code below, the expected output is:

Creating a thing
Type: thing
Setting thing then printing
thing expired? 0
   type is thing
Printing after a return to python
thing expired? 0
   type is thing


Creating a derived thing
Type: DerivedThing
Setting thing then printing
thing expired? 0
   type is DerivedThing
Printing after a return to python
thing expired? 0
   type is DerivedThing

The actual output is:

Creating a thing
Type: thing
Setting thing then printing
thing expired? 0
   type is thing
Printing after a return to python
thing expired? 0
   type is thing


Creating a derived thing
Type: DerivedThing
Setting thing then printing
thing expired? 0
   type is DerivedThing
Printing after a return to python
thing expired? 1

The issue is the last line, which indicates that the weak_ptr is no longer aware that the object still exists.

I tested a these variations:

Reproducible example code
C++ classes:

class thing : public std::enable_shared_from_this< thing >
{
    public:
        thing() = default;
        virtual ~thing() = default;

        virtual std::string get_type() const
        {
            return std::string("thing");
        }
};

class thing_holder
{
    public:
        thing_holder() = default;
        virtual ~thing_holder() = default;

        void print_thing() const
        {
            std::cout << "thing expired? " << f_thing.expired() << std::endl;
            if( ! f_thing.expired() )
            {
                std::cout << "   type is " << f_thing.lock()->get_type() << std::endl;
            }
            return;
        }

        void set_thing( std::shared_ptr< thing > a_thing_ptr )
        {
            f_thing = std::weak_ptr< thing >( a_thing_ptr );
            print_thing();  // print here to check the pointer while still in C++
            return;
        }

    private:
        std::weak_ptr< thing > f_thing;
};


Trampoline and Bindings:

class thing_trampoline : public thing //, public py::trampoline_self_life_support
{
    public:
        using thing::thing;

        std::string get_type() const override 
        {
            PYBIND11_OVERRIDE( std::string, thing, get_type, );
        }
};

std::list< std::string > export_thing( pybind11::module& mod )
{
    std::list< std::string > all_members;

    all_members.push_back( "Thing" );
    py::classh< thing, thing_trampoline >( mod, "Thing", "a thing" )
        .def( py::init< >() )
        .def( "get_type", &thing::get_type, "get the typename" )
        ;

    all_members.push_back( "ThingHolder" );
    py::class_< thing_holder >( mod, "ThingHolder", "holds things" )
        .def( py::init< >(), 
              py::return_value_policy::take_ownership )

        .def( "print_thing", &thing_holder::print_thing, "print thing" )
        .def( "set_thing", &thing_holder::set_thing, "set the thing" )
        ;

    return all_members;
}


Python class and executable script

class DerivedThing(dripline.core.Thing):
    def __init__(self):
        dripline.core.Thing.__init__(self)

    def get_type(self):
        return "DerivedThing"

if __name__ == '__main__':
    holder = thing_module.ThingHolder()

    print('Creating a thing')
    thing = thing_module.Thing()
    print(f'Type: {thing.get_type()}')
    
    print('Giving thing to the holder')
    holder.set_thing(thing)

    print('Printing after a return to python')
    holder.print_thing()

    print('\n')

    print('Creating a derived thing')
    derthing = DerivedThing()
    print(f'Type: {derthing.get_type()}')

    print('(Giving derived thing to the holder')
    holder.set_thing(derthing)

    print('Printing after a return to python')
    holder.print_thing()
Is this a regression? Put the last known working version here if it is.

Not a regression


RetroSearch is an open source project built by @garambo | Open a GitHub Issue

Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo

HTML: 3.2 | Encoding: UTF-8 | Version: 0.7.4