Boost Python没有看到内存归智能指针所有

时间:2019-06-27 17:45:32

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

当下面的析构函数销毁它的向量元素时,我得到了段错误触发。最初它是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;
};

每个向量元素子类型都是多态类,也继承自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和向量,并调用了assignVec(),但没有出现此问题。但是,一旦传入向量,其他任何东西都无法获得父级内存。

UPDATE2:

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

1 个答案:

答案 0 :(得分:0)

根据您提供的代码,并假设boost::python在这里没有错误,我想您可能是因为使用了移动语义:

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

在这里,您正在从左值引用移至向量vector&,然后移至您的成员。问题是:通常仅从r值引用(vector&&)中移出,因为它们不再受访问,因为唯一绑定到临时对象,或者如果该绑定通过创建r / x值引用显式地确认了移动。就像您使用std::move一样。

问题是:我敢打赌,assignVec的调用者可能不知道这一点,因为那为什么您还没有在签名中使用r值引用,以便调用者必须显式地std::move?我的假设是,您的呼叫者没有这样做,并且所做的不只是将价值从价值中转移出去的一件事:销毁它们。

您当然会问自己,为什么它会在析构函数中破坏呢?以我的经验,分段错误是在原因之后出现某种表达的,在这种情况下,我会通过仍然使用给定assignVec的向量来说出assignVec的调用者的不确定行为。