我正在尝试将对象存储在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 !
我完全失去了 - 看不出是什么导致了这一点。有什么输入吗?
答案 0 :(得分:11)
我运行了你的例子然后添加了一些我认为应该在del()
中保留的断言:
assert(!(v_param < v_ptr));
assert(!(v_ptr < v_param));
其中一人失败了!
我为operator<
挖掘了boost::shared_ptr
的实现并发现了一些奇怪的东西:它比较引用计数而不是内部指针!一点点挖掘发现了mailing list post关于这个问题的一些有用的链接到两个C ++文档:N1590解释了为什么人们认为这是一个好主意,而N2637解释了为什么它不是。
Boost人似乎还没有采用N2637推荐,但是C ++ 11已经采用了。所以我使用C ++ 11(g++ -std=c++0x
)再次构建了测试,删除了using namespace 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,只需为您的集合实现自己的自定义比较器,以便明智地比较指针:
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;