C++ Boost python看不见内存由智能指针拥有

C++ Boost python看不见内存由智能指针拥有,c++,move,smart-pointers,unique-ptr,boost-python,C++,Move,Smart Pointers,Unique Ptr,Boost Python,当下面的析构函数破坏它的向量元素时,我得到一个seg故障触发器。最初它是一个向量,但我将其更改为向量,此后每次崩溃都会发生: class Owner { Owner() = default; ~Owner() = default; // Seg faults void assignVec(std::vector<std::unique_ptr<Parent>>& vec) { _vec = std::move

当下面的析构函数破坏它的向量元素时,我得到一个seg故障触发器。最初它是一个
向量
,但我将其更改为
向量
,此后每次崩溃都会发生:

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;
};
所以整个继承层次结构都有虚拟析构函数

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>)
有人对如何继续调试这个问题有什么建议吗

更新:

我在单元测试中创建了一个小示例,创建了
Owner
和一个向量,调用
assignVec()
,但问题没有出现。但是,一旦传入向量,其他任何内容都无法获得父内存

更新2:


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

基于您给出的代码,假设
Boost::Python
在这里没有bug,我猜您使用移动语义可能是原因:

void assignVec(std::vector<std::unique_ptr<Parent>>& vec)
    {
        _vec = std::move(vec);
    }
void assignVec(标准::vector&vec)
{
_vec=std::move(vec);
}
在这里,您将从l值引用移动到向量,
向量&
移动到您的成员。问题是:通常一个只从r值引用(
vector&&
)移动,因为它们不能再访问了,因为它只绑定到临时变量,或者如果一个通过创建一个r/x值引用明确地确认移动,就像您使用
std::move
所做的那样

问题是:我打赌assignVec的调用者可能没有意识到这一点,因为为什么您在签名中没有使用r值引用,因此调用者必须显式地
std::move
?我的假设是,调用方不这样做,并且正在做不止一件合法的事情从值中移动:销毁它们


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

的向量,您对该类做了什么?您能举一个触发seg故障的类的最小使用示例吗?一个没有任何实例的简单定义当然可以not@Superlokkus如果我诚实的话,这是非常困难的。该代码是专有的。直到我将向量从Parent*改为unique,这个问题才存在。我会看看我是否能在一个单元中创建一个简单的示例test@Superlokkus我刚刚更新了所有者代码,并在底部添加了一个更新。child.h的第23行是什么?嗨,谢谢你指出这一点。我不是移动语义学方面的专家。签名应该是&&?我们还认为问题在于boostpython需要通知智能指针。显然,Boost Python不支持unique_ptr,我们正在努力让它识别共享_ptr(Boost和std)。根据函数的使用方式,我的一般建议是:当有疑问时,只需一个
常量t&
。如果您关心性能,请为
T&&
添加一个重载。或者,如果您有或可以有模板化代码,请使用转发引用(
template T&&
)。我建议您提供一般默认建议和解释。我对boost python不太熟悉,但我想您已经过多地了解了boost python必须依赖的生命周期细节,因为垃圾收集和语言,即运行时与python的交叉。对于向量中like
unique\u ptr
的不可复制元素,它或多或少是相同的,不同之处在于,您更被迫决定如何使用函数:函数背后的语义思想是调用方应该与传递的对象说再见吗?也没问题,只要使用
&&
,。还是他应该有选择?共享ptr是一种选择吗?为什么必须使用动态存储持续时间?为什么不让向量处理元素呢?为什么不让类所有者构建它们?!所有你需要背景的东西。这就是设计。我使用了移动语义,因为将创建第二个所有者实例,第一个所有者将把它的终端状态传递给新所有者。然后这两个所有者实例之间的某种东西,而不是使用它们的人,这意味着它不应该是公共函数,而应该在所有者类的move构造函数或move赋值操作符中完成。幸运的是,您甚至不必自己编写它,通常编译器会自动为您生成它。在编译器不确定的情况下,只需说move-ctor=default就可以让他放心;等等(请参阅)因此,在您的情况下,只需移动并分配所有者实例,您就完成了。
#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>)
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
void assignVec(std::vector<std::unique_ptr<Parent>>& vec)
    {
        _vec = std::move(vec);
    }