2011-11-20 27 views
6

Tôi đang cố gắng lưu trữ các đối tượng trong tập hợp :: std. Các đối tượng đó được tăng cường :: shared_ptr <>, đến từ môi trường python. thêm giá trị vào tập hợp sẽ không gây ra bất kỳ sự cố nào. Nhưng khi tôi cố gắng xóa một giá trị, mặc dù tôi đi qua cùng một tham chiếu, nó sẽ không hoạt động. Dưới đây là một ví dụ:boost :: python and set :: erase -> hành vi lạ

#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");  
} 

biên dịch:

%> 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 

và bây giờ, một kịch bản python nhỏ:

from test import * 

f = Foo() 
b = Bar() 

f.add(b) 

f.remove(b) 

Đây là kết quả:

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 ! 
  • tôi lưu trữ 0x8e89c58 bên trong các thiết lập và bên ngoài, chỉ trong trường hợp
  • Tôi đang đi qua các tài liệu tham khảo cùng với cả cuộc gọi (0x8e89c58)
  • chỉ để chắc chắn tôi kiểm tra nếu v == val
  • tôi cố gắng xóa bằng cách sử dụng v - nó không hoạt động
  • Tôi cố gắng xóa bằng cách sử dụng val - nó hoạt động!

Tôi hoàn toàn bị mất ở đó - không thể xem điều gì đang gây ra điều này. Bất kỳ đầu vào?

+0

Việc bạn sử dụng của "value" "val" và "v" tất cả các tên biến trong cùng một hàm làm cho mã của bạn không cần thiết phải làm theo. –

+0

thực sự, xin lỗi vì điều đó. Tôi hy vọng nó rõ ràng hơn bây giờ. – girodt

Trả lời

11

Tôi chạy ví dụ của bạn sau đó thêm một số khẳng định rằng tôi nghĩ nên giữ trong del():

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

Một trong số đó không thành công!

Tôi đào sâu vào việc triển khai operator< cho boost::shared_ptr và tìm thấy điều gì đó lạ: so sánh số lượng tham chiếu thay vì con trỏ nội bộ! Một chút đào tìm thấy một mailing list post về vấn đề này với một số liên kết hữu ích cho hai tài liệu C++: N1590 giải thích tại sao mọi người nghĩ đây là một ý tưởng hay, và N2637 giải thích tại sao nó không phải.

Có vẻ như những người Tăng cường chưa (chưa?) Đã áp dụng đề xuất N2637, nhưng C++ 11 có. Vì vậy, tôi đã xây dựng lại thử nghiệm của bạn bằng cách sử dụng C++ 11 (g++ -std=c++0x), khi đã xóa using namespace boost; để sử dụng std::shared_ptr. Điều này dẫn đến một thông báo lỗi mẫu-ridden khủng khiếp đó đã được giải quyết bằng cách thêm này ở phía trên cùng (dễ dàng có nguồn gốc từ boost/smart_ptr/shared_ptr.hpp):

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

Và nó hoạt động!

Nếu bạn không thể sử dụng C++ 11, chỉ cần thực hiện so sánh tùy chỉnh của riêng bạn cho thiết lập của bạn mà so sánh con trỏ sanely:

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

Sau đó, điều này sẽ làm việc:

set< shared_ptr<Bar>, SmartComparator<Bar> > v_set; 
+0

Chà. Tôi bị ấn tượng bởi chất lượng câu trả lời của bạn. Nó thực sự giải quyết vấn đề của tôi. Cảm ơn rất nhiều thời gian của bạn ! – girodt