2017-04-15 49 views
0

我花了一些時間試圖追蹤這個,但我在這裏有一個小例子,它顯示了我所看到的錯誤。如果我忽略重置行,它工作得很好。std :: unique_ptr在虛擬析構器上重置SIGABRT

#include <memory> 
#include <unordered_map> 
#include <iostream> 

class Base { 
    public: 
     virtual ~Base() = 0; 
}; 

Base::~Base(){} 

class D1 : public Base { 
    public: 
     ~D1(){} 
}; 

class D2 : public Base { 
    public: 
     ~D2(){} 
}; 

struct Foo { 
    using MyMap = std::unordered_map<std::size_t, std::unique_ptr<Base>>; 

    MyMap _test; 
}; 



int main(){ 
    Foo f; 
    /** Works fine **/ 
    f._test[12] = std::make_unique<D2>(); 
    f._test[1] = std::make_unique<D1>(); 

    D2 newD2; 
    f._test[12].reset(&newD2); 

    /** Execution reaches here **/ 
    std::cout<<"Foo!"<<std::endl; 

    /** Sigabrt on cleanup **/ 
    return 0; 
} 

程序上

Using built-in specs. 
COLLECT_GCC=g++ 
COLLECT_LTO_WRAPPER=/usr/lib/gcc/i686-pc-linux-gnu/6.3.1/lto-wrapper 
Target: i686-pc-linux-gnu 
Configured with: /build/gcc/src/gcc/configure --prefix=/usr --libdir=/usr/lib --libexecdir=/usr/lib --mandir=/usr/share/man --infodir=/usr/share/info --with-bugurl=https://bugs.archlinux.org/ --enable-languages=c,c++,ada,fortran,go,lto,objc,obj-c++ --enable-shared --enable-threads=posix --enable-libmpx --with-system-zlib --with-isl --enable-__cxa_atexit --disable-libunwind-exceptions --enable-clocale=gnu --disable-libstdcxx-pch --disable-libssp --enable-gnu-unique-object --enable-linker-build-id --enable-lto --enable-plugin --enable-install-libiberty --with-linker-hash-style=gnu --enable-gnu-indirect-function --disable-multilib --disable-werror --enable-checking=release 
Thread model: posix 
gcc version 6.3.1 20170306 (GCC) 

編譯罰款沒有警告或錯誤。但是,當程序運行並退出時,它似乎在清理時發出sigbart。 Valgrind有以下說

==24694== Memcheck, a memory error detector 
==24694== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al. 
==24694== Using Valgrind-3.12.0 and LibVEX; rerun with -h for copyright info 
==24694== Command: ./test 
==24694== 
Foo! 
pure virtual method called 
terminate called without an active exception 
==24694== 
==24694== Process terminating with default action of signal 6 (SIGABRT): dumping core 
==24694== at 0x427E502: raise (in /usr/lib/libc-2.25.so) 
==24694== by 0x427FCD6: abort (in /usr/lib/libc-2.25.so) 
==24694== by 0x40CC6CE: __gnu_cxx::__verbose_terminate_handler() (vterminate.cc:95) 
==24694== by 0x40CA063: __cxxabiv1::__terminate(void (*)()) (eh_terminate.cc:47) 
==24694== by 0x40CA0DC: std::terminate() (eh_terminate.cc:57) 
==24694== by 0x40CAED3: __cxa_pure_virtual (pure.cc:50) 
==24694== by 0x8049A29: std::default_delete<Base>::operator()(Base*) const (in /home/aryan/Desktop/Gists/test) 
==24694== by 0x804A946: std::unique_ptr<Base, std::default_delete<Base> >::~unique_ptr() (in /home/aryan/Desktop/Gists/test) 
==24694== by 0x804A74C: std::pair<unsigned int const, std::unique_ptr<Base, std::default_delete<Base> > >::~pair() (in /home/aryan/Desktop/Gists/test) 
==24694== by 0x804A764: void __gnu_cxx::new_allocator<std::pair<unsigned int const, std::unique_ptr<Base, std::default_delete<Base> > > >::destroy<std::pair<unsigned int const, std::unique_ptr<Base, std::default_delete<Base> > > >(std::pair<unsigned int const, std::unique_ptr<Base, std::default_delete<Base> > >*) (in /home/aryan/Desktop/Gists/test) 
==24694== by 0x804A3D6: void std::allocator_traits<std::allocator<std::pair<unsigned int const, std::unique_ptr<Base, std::default_delete<Base> > > > >::destroy<std::pair<unsigned int const, std::unique_ptr<Base, std::default_delete<Base> > > >(std::allocator<std::pair<unsigned int const, std::unique_ptr<Base, std::default_delete<Base> > > >&, std::pair<unsigned int const, std::unique_ptr<Base, std::default_delete<Base> > >*) (in /home/aryan/Desktop/Gists/test) 
==24694== by 0x8049F65: std::__detail::_Hashtable_alloc<std::allocator<std::__detail::_Hash_node<std::pair<unsigned int const, std::unique_ptr<Base, std::default_delete<Base> > >, false> > >::_M_deallocate_node(std::__detail::_Hash_node<std::pair<unsigned int const, std::unique_ptr<Base, std::default_delete<Base> > >, false>*) (in /home/aryan/Desktop/Gists/test) 
==24694== 
==24694== HEAP SUMMARY: 
==24694==  in use at exit: 32 bytes in 2 blocks 
==24694== total heap usage: 8 allocs, 6 frees, 20,028 bytes allocated 
==24694== 
==24694== LEAK SUMMARY: 
==24694== definitely lost: 0 bytes in 0 blocks 
==24694== indirectly lost: 0 bytes in 0 blocks 
==24694==  possibly lost: 0 bytes in 0 blocks 
==24694== still reachable: 32 bytes in 2 blocks 
==24694==   suppressed: 0 bytes in 0 blocks 
==24694== Rerun with --leak-check=full to see details of leaked memory 
==24694== 
==24694== For counts of detected and suppressed errors, rerun with: -v 
==24694== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0) 
Aborted (core dumped) 

至於這個問題,我錯過了明顯的明顯或這是一個錯誤?我沒有其他的編譯器在手,現在來測試..

回答

3
D2 newD2; 
f._test[12].reset(&newD2); 

你給unique_ptr指向與自動一生的變量。這是一個不行。

unique_ptr超出範圍就試圖做delete ptr;ptr從來沒有對new分配讓你delete失敗,你會得到一個不錯的SIGABRT。無論如何,newD2將自行銷燬,因爲它具有自動生命期。

這是未定義的行爲,有或沒有虛擬,虛擬可能是SIGABRT的觸發器。

+0

這是那些時刻之一。 Ty儘快回答!爲了我自己的緣故,你是否從valgrind輸出中看到了這一點,或者你是否從代碼中發現了我的錯誤?我是C++的新手,很難破譯這些錯誤:) – arynaq

+2

@arynaq從你的代碼,它只是練習蕾。而已。 –

0

不要與沒有被運營商分配或創建了的std :: make_shared的std ::對象make_unique使用smart_pointers。

在你的例子中newD2有其確定的範圍。當它離開它的範圍時(返回之後)它的析構函數會自動調用。

在C++中,RAII保證當對象的析構函數超出其範圍時被調用。

+0

智能指針本身不必刪除它們的指尖。這只是默認設置。有一個智能指針的動物園,你幾乎可以讓他們做任何你認爲合適的事情。 – rubenvb