c++ - Boost python 看不到内存归智能指针所有

标签 c++ move smart-pointers unique-ptr boost-python

当下面的析构函数破坏它的 vector 元素时,我得到一个段错误触发。最初它是一个 vector<Parent> 但我将其更改为 vector<unique_ptr<Parent>> 并且从那时起每次都会发生崩溃:

class Owner
{
    Owner() = default;
    ~Owner() = default;    // Seg faults

    void assignVec(std::vector<std::unique_ptr<Parent>>& vec)
    {
        _vec = std::move(vec);
    }

    std::vector<std::unique_ptr<Parent>> _vec;
};

每个 vector 元素子类型都是一个多态类,同样继承自boost::python::wrapper

class Child: public Parent, public boost::python::wrapper<Parent>
{
    Child();
    virtual ~Child() = default;
};

哪里:

class Parent
{
    Parent() = default;
    virtual ~Parent() = default;
};

所以整个继承层次确实有虚析构函数。

GDB 回溯显示:

#0  0x00007ffff636b207 in __GI_raise (sig=sig@entry=6) at ../nptl/sysdeps/unix/sysv/linux/raise.c:55
#1  0x00007ffff636c8f8 in __GI_abort () at abort.c:90
#2  0x00007ffff63add27 in __libc_message (do_abort=do_abort@entry=2, fmt=fmt@entry=0x7ffff64bf678 "*** Error in `%s': %s: 0x%s ***\n") at ../sysdeps/unix/sysv/linux/libc_fatal.c:196
#3  0x00007ffff63b6489 in malloc_printerr (ar_ptr=0x7ffff66fb760 <main_arena>, ptr=<optimized out>, str=0x7ffff64bcd31 "free(): invalid pointer", action=3) at malloc.c:5004
#4  _int_free (av=0x7ffff66fb760 <main_arena>, p=<optimized out>, have_lock=0) at malloc.c:3843
#5  0x00007fffc373972f in Child::~Child (this=0x2742b10, __in_chrg=<optimized out>) at Child.h:23
#6  0x000000000045694e in std::default_delete<Parent>::operator() (this=0x11922e0, __ptr=0x2742b10) at /opt/gcc-8.2.0/include/c++/8.2.0/bits/unique_ptr.h:81
#7  0x0000000000454c27 in std::unique_ptr<Parent, std::default_delete<Parent> >::~unique_ptr (this=0x11922e0, __in_chrg=<optimized out>) at /opt/gcc-8.2.0/include/c++/8.2.0/bits/unique_ptr.h:274
#8  0x000000000045a882 in std::_Destroy<std::unique_ptr<Parent, std::default_delete<Parent> > > (__pointer=0x11922e0) at /opt/gcc-8.2.0/include/c++/8.2.0/bits/stl_construct.h:98
#9  0x0000000000458f67 in std::_Destroy_aux<false>::__destroy<std::unique_ptr<Parent, std::default_delete<Parent> >*> (__first=0x11922e0, __last=0x11922e8) at /opt/gcc-8.2.0/include/c++/8.2.0/bits/stl_construct.h:108
#10 0x0000000000457636 in std::_Destroy<std::unique_ptr<Parent, std::default_delete<Parent> >*> (__first=0x11922e0, __last=0x11922e8) at /opt/gcc-8.2.0/include/c++/8.2.0/bits/stl_construct.h:137
#11 0x000000000045584d in std::_Destroy<std::unique_ptr<Parent, std::default_delete<Parent> >*, std::unique_ptr<Parent, std::default_delete<Parent> > > (__first=0x11922e0, __last=0x11922e8)
    at /opt/gcc-8.2.0/include/c++/8.2.0/bits/stl_construct.h:206
#12 0x000000000049b53d in std::vector<std::unique_ptr<Parent, std::default_delete<Parent> >, std::allocator<std::unique_ptr<Parent, std::default_delete<Parent> > > >::~vector (this=0x7fffffffc4a8, __in_chrg=<optimized out>)
    at /opt/gcc-8.2.0/include/c++/8.2.0/bits/stl_vector.h:567
#13 0x000000000048c677 in Owner::~Owner (this=0x7fffffffc4a8, __in_chrg=<optimized out>)

在第 5 帧中打印 this 确实显示了一个有效对象。 free()的第4帧源码为:

static void _int_free(mstate av, mchunkptr p, int have_lock)                      
{                                                                     
  INTERNAL_SIZE_T size;        /* its size */                         
  mfastbinptr*    fb;          /* associated fastbin */               
  mchunkptr       nextchunk;   /* next contiguous chunk */            
  INTERNAL_SIZE_T nextsize;    /* its size */                         
  int             nextinuse;   /* true if nextchunk is used */        
  INTERNAL_SIZE_T prevsize;    /* size of previous contiguous chunk */
  mchunkptr       bck;         /* misc temp for linking */            
  mchunkptr       fwd;         /* misc temp for linking */            

  const char *errstr = NULL;
  int locked = 0;

  size = chunksize(p);

  /* Little security check which won't hurt performance: the          
     allocator never wrapps around at the end of the address space.   
     Therefore we can exclude some size values which might appear
     here by accident or by "design" from some intruder.  */        
  if (__builtin_expect ((uintptr_t) p > (uintptr_t) -size, 0)    
      || __builtin_expect (misaligned_chunk (p), 0))
    {  
      errstr = "free(): invalid pointer";
    errout:      
      if (have_lock || locked)
        (void)mutex_unlock(&av->mutex);                               
      malloc_printerr (check_action, errstr, chunk2mem(p), av);      // CRASHES HERE

有没有人对如何进行调试有任何建议?

更新:

我在单元测试中创建了一个小例子,创建Owner和一个vector,调用assignVec()并没有出现问题。但是,一旦传入 vector ,就没有其他任何东西获得 Parent 内存。

更新 2:

我们认为问题在于 boost python 需要被告知智能指针。显然 Boost Python 不支持 unique_ptr,我们正在努力让它识别 shared_ptr(Boost 和 std),即使使用典型的寄存器技术也是如此。

最佳答案

根据您提供的代码并假设 boost::python 没有错误,我猜您对 move 语义的使用可能是原因:

void assignVec(std::vector<std::unique_ptr<Parent>>& vec)
    {
        _vec = std::move(vec);
    }

在这里,您正在从左值引用 move 到 vector ,vector& 到您的成员。问题是:通常只从 r 值引用 (vector&&) move ,因为它们不能再被访问,因为唯一绑定(bind)到临时对象,或者如果一个人通过创建 r/x 明确承认 move -values 引用,就像您使用 std::move 所做的那样。

问题是:我敢打赌你调用 assignVec 的人可能不知道这一点,因为那你为什么还没有在签名中使用右值引用,这样调用者就必须 std::move明确?我的假设是,您的来电者没有,并且所做的不仅仅是一件合法的事情,可以从值(value)中转移:破坏它们。

当然你会问自己,为什么它会在析构函数中 break then?根据我的经验,段错误会在原因之后出现一些表达式,在这种情况下,我会说 assignVec 的调用者的未定义行为仍然使用给 assignVec 的 vector 。

关于c++ - Boost python 看不到内存归智能指针所有,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56796264/

相关文章:

c++ pthread join有时不起作用

c++ - 是否有将 'methods' 与成员隔离的设计模式?

c++ - 如何从可变参数模板参数创建 std::tuple<>?

perl - move 文件时未定义的子例程

Java每0.5秒在动画中 move jlabel

c++ - Qt4 QSettings 读取具有多个值的数组

c++ - 根据函数签名将引用作为左值/右值传递

c++ - 是否有内置深层复制功能的作用域指针?

c++ - 句柄和智能指针一样吗?

c++ - 与 C++ 中的普通指针相比,智能指针的开销是多少?