2011-11-20 33 views
6

我試圖將對象存儲在std :: set中。這些對象是來自python環境的boost :: shared_ptr <>。增加值的設置不會造成任何麻煩。但是,當我嘗試擦除一個值時,即使我傳遞了相同的參考,它也不起作用。這裏有一個例子:boost :: python和set :: erase - >奇怪的行爲

#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擦除 - 它的工作原理!

我完全失去了那裏 - 看不到是什麼造成了這一點。任何輸入?

+0

您在使用將「value」,「val」和「v」全部作爲同一個函數中的變量名稱使您的代碼難以遵循。 –

+0

的確如此,對不起。我希望現在更清楚。 – girodt

回答

11

我跑你的例子,然後增加了一些說法,我認爲應該在del()持有:

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

其中之一失敗!

我爲boost::shared_ptr找到operator<的實現,發現有些奇怪:它比較引用計數而不是內部指針!有一點挖掘發現有關這個問題的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; 
+0

哇。我的回答質量給我留下了深刻的印象。它確實解決了我的問題。非常感謝您的時間! – girodt