boost :: python和set :: erase - >奇怪的行为 [英] boost::python and set::erase -> weird behaviour

查看:103
本文介绍了boost :: python和set :: erase - >奇怪的行为的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图将对象存储在std :: set中。这些对象是boost :: shared_ptr<>,来自python环境。向该集合添加值不会导致任何故障。但是当我试图擦除一个值,即使我传递相同的引用,它将无法工作。下面是一个示例:

I'm trying to store objects in a std::set. Those objects are boost::shared_ptr<>, coming from the python environment. adding values to the set won't cause any troubles. But when I try to erase a value, even though I'm passing the very same reference, it won't 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");    
}

编译:

%> 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脚本:

and now, a small python script :

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存储在集合和外部, li>
  • 我向两个调用(0x8e89c58)

  • 传递相同的引用,以确保检查v == val

  • 我尝试使用v删除它不工作

  • 我尝试使用val擦除它工作!

    • I store 0x8e89c58 inside the set and outside, just in case
    • I'm passing the same reference to both calls (0x8e89c58)
    • just to make sure i check if v == val
    • I try to erase by using v -- it doesn't work
    • I try to erase by using val -- it works !
    • 我完全失去了 - 看不到造成这种情况的原因。任何输入?

      I'm completely lost there - can't see what is causing this. Any input ?

      推荐答案

      我跑了你的例子,然后添加了一些断言,我认为应该在 del )

      I ran your example then added some assertions that I thought should hold in del():

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

      其中一个失败!

      挖掘运算符< boost :: shared_ptr 的实现,发现了一些奇怪的:它比较引用计数,而不是内部指针!一个小小的挖掘发现了一个邮件列表帖子关于这个问题,一些有用的链接到两个C +文件:N1590,这解释了为什么人们认为这是一个好主意,而N2637它解释了为什么不是。

      I dug into the implementation of operator< for boost::shared_ptr and found something strange: it compares the reference counts rather than the internal pointers! A little digging found a mailing list post about this issue with some helpful links to two C++ documents: N1590 which explains why people thought this was a good idea, and N2637 which explains why it wasn't.

      看来Boost人没有)采纳了N2637的建议,但是C ++ 11有。所以我使用C ++ 11( g ++ -std = c ++ 0x )再次构建了测试,使用命名空间boost删除了; ,以便使用 std :: shared_ptr 。这导致一个可怕的模板错误消息,它是通过添加这个在顶部解决的(容易从 boost / smart_ptr / shared_ptr.hpp 派生):

      It seems that the Boost people have not (yet?) adopted the N2637 recommendation, but C++11 has. So I built your test again using C++11 (g++ -std=c++0x), having removed using namespace boost; so as to use std::shared_ptr. This resulted in a horrible template-ridden error message which was solved by adding this at the top (easily derived from boost/smart_ptr/shared_ptr.hpp):

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

      而且有效!

      如果您不能使用C ++ 11,只需为您的集合实施自己的自定义比较器,即可完全比较指针:

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

      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;
      

      这篇关于boost :: python和set :: erase - &gt;奇怪的行为的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆