Boost :: python and set :: erase & # 8594; strange behavior

I am trying to save objects in std :: set. These objects are boost :: shared_ptr <>, coming from the python environment. adding values โ€‹โ€‹to the set will not cause any problems. But when I try to erase the value, although I am passing the same link, this will not work. Here is an example:

#include <set> #include <iostream> #include <boost/shared_ptr.hpp> #include <boost/python.hpp> using namespace std; using namespace boost; using namespace boost::python; struct Bar { Bar() {} }; struct Foo { set< shared_ptr<Bar> > v_set; shared_ptr<Bar> v_ptr; Foo() {} void add( shared_ptr<Bar> v_param ) { cout << "storing " << v_param << "in v_set and v_ptr" << endl; v_set.insert(v_param); v_ptr = v_param; } void del( shared_ptr<Bar> v_param ) { cout << "deleting " << v_param << endl; if (v_param == v_ptr) { cout << "v_param == v_ptr" << endl; } else { cout << "v_param != v_ptr" << endl; } cout << "erasing from v_set using v_param" << endl; if (v_set.erase(v_param) == 0) { cout << "didn't erase anything" << endl; } else { cout << "erased !" << endl; } cout << "erasing from v_set using v_ptr" << endl; if (v_set.erase(v_ptr) == 0) { cout << "didn't erase anything" << endl; } else { cout << "erased !" << endl; } } }; BOOST_PYTHON_MODULE (test) { class_< Foo, shared_ptr<Foo> >("Foo") .def("add",&Foo::add) .def("remove",&Foo::del); class_< Bar, shared_ptr<Bar> >("Bar"); } 

compilation:

 %> gcc -pthread -fno-strict-aliasing -march=i686 -mtune=generic -O2 -pipe -DNDEBUG -march=i686 -mtune=generic -O2 -pipe -fPIC -I/usr/include/python2.7 -c test.cpp -o test.o %> g++ -pthread -shared -Wl,--hash-style=gnu -Wl,--as-needed build/temp.linux-i686-2.7/test.o -L/usr/lib -lboost_python -lpython2.7 -o test.so 

and now a little python script:

 from test import * f = Foo() b = Bar() f.add(b) f.remove(b) 

Here is the result:

 storing 0x8c8bc58in v_set and v_ptr deleting 0x8c8bc58 v_param == v_ptr erasing from v_set using v_param didn't erase anything erasing from v_set using v_ptr erased ! 
  • I store 0x8e89c58 inside the set and outside, just in case
  • I pass the same link to both calls (0x8e89c58)
  • to make sure i check if v == val
  • I try to erase with v - it does not work.
  • I'm trying to erase using val - it works!

I was completely lost there - I donโ€™t see what causes this. Any input?

+6
source share
1 answer

I ran your example and added some statements that I thought should be in del() :

 assert(!(v_param < v_ptr)); assert(!(v_ptr < v_param)); 

One of them failed!

I put operator< for boost::shared_ptr in the implementation and found something strange: it compares the number of links, not the internal pointers! With a bit of digging, I found a mailing list about this problem with some useful links to two C ++ documents: N1590, which explains why people thought it was a good idea, and N2637, which explains why it wasnโ€™t.

It seems that Boost people have not yet accepted recommendation N2637, but C ++ 11. Therefore, I again built the test using C ++ 11 ( g++ -std=c++0x ), removing using namespace boost; to use std::shared_ptr . This led to a terrible template error message, which was resolved by adding this at the top (easily got from boost/smart_ptr/shared_ptr.hpp ):

 template<class T> inline T * get_pointer(std::shared_ptr<T> const & p) { return p.get(); } 

And it works!

If you can't use C ++ 11, just use your own custom comparator for your set, which compares pointers:

 template <typename T> struct SmartComparator { bool operator()(shared_ptr<T> const& lhs, shared_ptr<T> const& rhs) { return lhs.get() < rhs.get(); } }; 

Then it will work:

 set< shared_ptr<Bar>, SmartComparator<Bar> > v_set; 
+11
source

Source: https://habr.com/ru/post/901950/


All Articles