我正在尝试将对象存储在std :: set中.这些对象是来自
python环境的boost :: shared_ptr<>.向集合中添加值不会导致任何麻烦.但是当我尝试擦除一个值时,即使我传递了相同的引用,它也无法工作.这是一个例子:
#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"); }
编译:
%> 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
而现在,一个小的python脚本:
from test import * f = Foo() b = Bar() f.add(b) f.remove(b)
结果如下:
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 !
>我将0x8e89c58存储在集合内外,以防万一
>我正在向两个调用传递相同的引用(0x8e89c58)
>只是为了确保我检查是否v == val
>我尝试使用v擦除 – 它不起作用
>我尝试使用val擦除 – 它有效!
我完全迷失在那里 – 看不出是什么导致了这一点.有什么输入?
解决方法
我运行你的例子,然后添加了一些我认为应该在del()中保存的断言:
assert(!(v_param < v_ptr)); assert(!(v_ptr < v_param));
其中一个失败了!
我挖掘了运算符<的实现.对于boost :: shared_ptr并发现了一些奇怪的东西:它比较引用计数而不是内部指针!一个小小的挖掘发现了一个关于这个问题的mailing list post以及一些有用的链接到两个C文件:N1590解释了为什么人们认为这是一个好主意,而N2637解释了为什么它不是.
似乎Boost人还没有采用N2637推荐,但是C 11已经采用了N2637.所以我使用C 11(g -std = c 0x)再次构建了测试,删除了使用命名空间boost;以便使用std :: shared_ptr.这导致了一个可怕的模板错误消息,通过在顶部添加它来解决(很容易从boost / smart_ptr / shared_ptr.hpp派生):
template<class T> inline T * get_pointer(std::shared_ptr<T> const & p) { return p.get(); }
它的工作原理!
如果你不能使用C 11,只需为你的set实现自己的自定义比较器,它可以比较指针:
template <typename T> struct SmartComparator { bool operator()(shared_ptr<T> const& lhs,shared_ptr<T> const& rhs) { return lhs.get() < rhs.get(); } };
然后这将工作:
set< shared_ptr<Bar>,SmartComparator<Bar> > v_set;