2017-04-15 1 views
0

Ich habe einige Zeit versucht, dies zu verfolgen, aber ich habe hier ein kleines Beispiel, das den Fehler zeigt, den ich sehe. Wenn ich die Zeile mit Reset weglasse, funktioniert es gut.std :: unique_ptr SIGABRT auf virtuellen Destruktor zurücksetzen

#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; 
} 

Das Programm stellt auf

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) 

ohne Warnungen oder Fehler in Ordnung. Aber wenn das Programm ausgeführt und beendet wird, scheint es sich um Cleanup zu handeln. Valgrind Folgendes

==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) 

Was die Frage zu sagen, bin ich etwas fehlt eklatant oder ist das ein Fehler? Ich habe keine anderen Compiler zur Hand gerade jetzt zu testen ..

Antwort

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

Sie die unique_ptr ein Zeiger auf eine Variable mit automatischer Lebensdauer geben. Das ist ein Nein, nein.

Wenn die unique_ptr den Gültigkeitsbereich verlässt versucht, es zu tun delete ptr; aber ptr nie mit new zugewiesen wurde, damit Ihre delete fehlschlägt und Sie einen schönen SIGABRT bekommen. newD2 wird von selbst zerstört, weil es sowieso automatische Lebensdauer hat.

Dies ist undefiniertes Verhalten mit oder ohne das virtuelle, das virtuelle könnte der Auslöser für das SIGABRT gewesen sein.

+0

Dies ist einer jener d'oh Momente. Ty für die schnelle Antwort! Um meinetwillen, hast du das aus der Valgrind-Ausgabe gesehen oder hast du meinen Fehler aus dem Code verstanden? Ich bin neu in C++ und schwer zu entziffern diese Fehler :) – arynaq

+2

@arynaq Von Ihrem Code ist es nur Übung Knospe. Nichts mehr. –

0

nicht smart_pointers mit Objekten verwendet werden, die durch neue Betreiber nicht zugeteilt wurden oder mit std :: erstellt oder std :: make_unique make_shared.

In Ihrem Beispiel newD2 hat seinen gut festgelegten Umfang. Wenn es seinen Geltungsbereich (nach der Rückkehr) verlässt, wird sein Destruktor automatisch aufgerufen.

In C++ garantiert RAII, dass der Destruktor des Objekts aufgerufen wird, wenn er seinen Gültigkeitsbereich verlässt.

+0

Smartpointer müssen ihre Pointees nicht per se löschen. Das ist nur der Standard. Es gibt einen ganzen Zoo von intelligenten Zeigern und Sie können sie ziemlich machen, was Sie für richtig halten. – rubenvb

Verwandte Themen