[C++-sig] boost::python and boost::shared_ptr strict weak ordering problem

Markus Woschank markus.woschank at gmail.com
Fri Aug 1 23:55:51 CEST 2008


Hi list,

I'm getting a strange behaviour with shared_ptr objects as arguments of 
wrapped C++ functions.
The problem occurs when i try to use the shared_ptr objects in a 
std::set which (AFAIK) uses
strict weak ordering equivalence [ !(a<b) && !(b<a) ]. The problem also 
only seems to occur if
there are different calls to C++ from python, while the C++ code holds a 
shared_ptr somewhere.

I'm using boost 1.35.0.

Here is a sample program that should demonstrate my problem

C++ code:
---
class Toast : boost::noncopyable
{
  public:
    typedef boost::shared_ptr<Toast> ptr;

    static ptr create()
    { return ptr( new Toast() ); }

  private:
    Toast() {}
};

bool ptr_equals_last(Toast::ptr p)
{
  static Toast::ptr last;
  bool equal = !(p<last) && !(last<p);
  last = p;
  return equal;
}

BOOST_PYTHON_MODULE(ptr_test)
{
  using namespace boost::python;

  class_< Toast, Toast::ptr, boost::noncopyable >("Toast",no_init)
    .def("create",&Toast::create)
    .staticmethod("create");
  ;

  def("ptr_equals_last",ptr_equals_last);
}
---
[ also available (for some time) on http://tmp.netst.at/python_module.cpp ]

python test and output:
---
Python 2.5.2 (r252:60911, Aug  1 2008, 22:31:18)
[GCC 4.1.2 (Gentoo 4.1.2)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
 >>> from ptr_test import Toast,ptr_equals_last
 >>>
 >>> t = Toast.create() # instance for testing
 >>> t
<ptr_test.Toast object at 0x7f10e95b6578>
 >>> ptr_equals_last(None) # should return True ( empty == empty => 
equivalent )
True
 >>> ptr_equals_last(None) # should return True ( empty == empty => e. )
True
 >>>
 >>> ptr_equals_last(t) # should return False ( empty != t => not e. )
False
 >>> ptr_equals_last(t) # should return True ( t == t => e. )
False
 >>> ptr_equals_last(t) # should return True ( t == t => e. )
False
 >>> ptr_equals_last(None) # should return False ( t != empty => not e. )
False
 >>> ptr_equals_last(None) # should return True ( empty == empty => e. )
True
---
[ also available (for some time) on http://tmp.netst.at/test.py ]

PS: After debugging a little bit my wild guess is, that boost.python 
uses the shared_ptr objects with
custom deleter function that decrements the python refcount. And such 
custom shared_ptrs are created
every time a C++ function with an shared_ptr argument is called (while 
incrementing the python refcount).
Which seems to work fine but (IMO) breaks the less than operator of 
boost::shared_ptr documented at
[http://www.boost.org/doc/libs/1_35_0/libs/smart_ptr/shared_ptr.htm#functions] 
- but as already said, it's
only a wild guess.

Cheers,
Markus




More information about the Cplusplus-sig mailing list