虚函数和虚析构函数

1.               虚析构函数简介

虚析构函数的使用非常普遍。如QT中的QObject:

class Q_CORE_EXPORT QObject

{

    Q_OBJECT

    Q_PROPERTY(QString objectName READ objectName WRITE setObjectName)

    Q_DECLARE_PRIVATE(QObject)

 

public:

    Q_INVOKABLE explicit QObject(QObject *parent=0);

    virtual ~QObject();

...

}

虚析构函数的具体作用我所理解的就是避免内存泄露。

但是虚析构函数和虚函数在运行时期行为不一样,有其自己的特殊性。

2.               虚析构例子

如下面的例子:

/*Sample1*/

#include<iostream>

#include<stdlib.h>

using namespace std;

class Base

{

public:

    Base() {};

    virtual ~Base() { cout << "Destructor of Base!" << endl; }; 

 

    virtual void funcA() { cout << "funcA of Base!" << endl; };

};

 

class Derived : public Base

{

public:

    Derived() {};

    ~Derived() { cout << "Destructor of Derived!" << endl; }; 

 

    void funcA() { cout << "funcA of Derived!" << endl; };

};

 

int main()

{

Base *pderived =new Derived;

pderived->funcA();

delete pderived;

return 0;

}

运行后输出:

funcA of Derived!

Destructor of Derived!

Destructor of Base!

可以看到,虚函数只是调用了子类的虚函数。而父类和子类的虚析构函数都被调用了!

虚函数的调用通常只会调用到一个函数。而虚析构函数,则是“最底层的派生类的析构函数最先被调用,然后各个基类的析构函数被调用”。这句话援引自

《effective   C++》   14款。全文是“这个定义是必需的,因为虚析构函数工作的方式是:最底层的派生类的析构函数最先被调用,然后各个基类的析构函数被调用。这就是说,即使是抽象类,编译器也要产生对~awov的调用,所以要保证为它提供函数体。如果不这么做,链接器就会检测出来,最后还是得回去把它添上。”  

3.               虚析构函数的汇编分析

但是到目前为止,我们仅仅知道有这么一回事。但是,为什么是这么一回事?

把上面的代码修改下,输出其汇编:

/*Sample2*/

using namespace std;

class Base

{

public:

    //Base() {};

    virtual ~Base() {};// { cout << "Destructor of Base!" << endl; };

    virtual void funcA() {};// { cout << "funcA in class Base!" << endl; };

};

 

class Derived : public Base

{

public:

    //Derived() {};

    ~Derived() {}; // { cout << "Destructor of Derived!" << endl; };

    void funcA()  {}; //{ cout << "funcA in class Derived!" << endl; };

};

 

int main()

{

     Base *pderived =new Derived;

     //pderived->funcA();

     delete pderived;

    

     return 0;

}

对上述代码,针对是否使用了语句delete pderived使用g++ -S分别输出其汇编代码。

首先是没有调用delete pderived的汇编代码:

main:

.LFB968:

        .cfi_startproc

        .cfi_personality 0x0,__gxx_personality_v0

        pushl   %ebp

        .cfi_def_cfa_offset 8

        movl    %esp, %ebp

        .cfi_offset 5, -8

        .cfi_def_cfa_register 5

        andl    $-16, %esp

        pushl   %ebx

        subl    $44, %esp

        movl    $4, (%esp)

        .cfi_escape 0x10,0x3,0x7,0x55,0x9,0xf0,0x1a,0x9,0xfc,0x22

        call    _Znwj

        movl    %eax, %ebx

        movl    %ebx, %eax

        movl    %eax, (%esp)

        call    _ZN7DerivedC1Ev

        movl    %ebx, %eax

        movl    %eax, 28(%esp)

        movl    $0, %eax

.L38:

        addl    $44, %esp

        popl    %ebx

        movl    %ebp, %esp

        popl    %ebp

        ret

        .cfi_endproc

 

调用了delete pderived的汇编代码:

main:

.LFB968:

        .cfi_startproc

        .cfi_personality 0x0,__gxx_personality_v0

        pushl   %ebp

        .cfi_def_cfa_offset 8

        movl    %esp, %ebp

        .cfi_offset 5, -8

        .cfi_def_cfa_register 5

        andl    $-16, %esp

        pushl   %ebx

        subl    $44, %esp

        movl    $4, (%esp)

        .cfi_escape 0x10,0x3,0x7,0x55,0x9,0xf0,0x1a,0x9,0xfc,0x22

        call    _Znwj

        movl    %eax, %ebx

        movl    %ebx, %eax

        movl    %eax, (%esp)

        call    _ZN7DerivedC1Ev

        movl    %ebx, %eax

        movl    %eax, 28(%esp)

        cmpl    $0, 28(%esp)

        je      .L39

.L40:

.L38:

        movl    28(%esp), %eax

        movl    (%eax), %eax

        addl    $4, %eax

        movl    (%eax), %edx

        movl    28(%esp), %eax

        movl    %eax, (%esp)

        call    *%edx

.L39:

        movl    $0, %eax

        addl    $44, %esp

        popl    %ebx

        movl    %ebp, %esp

        popl    %ebp

        ret

        .cfi_endproc

注意到这两段代码有一个区别是,没有调用delete pderived的汇编代码仅仅使用了一次call指令(call   _ZN7DerivedC1Ev),而使用了两次(call    _ZN7DerivedC1Ev, call    *%edx)。

由此我们可以推断出,delete pderived的操作由call    *%edx触发的。

那么,call    *%edx到底做了些什么呢?

 

3.1           call    *%edx

先附上代码,后续补上。

 

     .file    "virtual.cpp"

     .local  _ZStL8__ioinit

     .comm _ZStL8__ioinit,1,1

     .section   .rodata

.LC0:

     .string "Destructor of Derived!"

     .text

.globl _Z5hellov

     .type  _Z5hellov, @function

_Z5hellov:

.LFB957:

     .cfi_startproc

     .cfi_personality 0x0,__gxx_personality_v0

     pushl  %ebp

     .cfi_def_cfa_offset 8

     movl   %esp, %ebp

     .cfi_offset 5, -8

     .cfi_def_cfa_register 5

     subl    $24, %esp

     movl   $.LC0, 4(%esp)

     movl   $_ZSt4cout, (%esp)

     call     _ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc

     movl   $_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_, 4(%esp)

     movl   %eax, (%esp)

     call     _ZNSolsEPFRSoS_E

     leave

     ret

     .cfi_endproc

.LFE957:

     .size   _Z5hellov, .-_Z5hellov

     .section   .text._ZN4BaseD2Ev,"axG",@progbits,_ZN4BaseD2Ev,comdat

     .align 2

     .weak _ZN4BaseD2Ev

     .type  _ZN4BaseD2Ev, @function

_ZN4BaseD2Ev:

.LFB959:

     .cfi_startproc

     .cfi_personality 0x0,__gxx_personality_v0

     pushl  %ebp

     .cfi_def_cfa_offset 8

     movl   %esp, %ebp

     .cfi_offset 5, -8

     .cfi_def_cfa_register 5

     subl    $24, %esp

     movl   8(%ebp), %eax

     movl   $_ZTV4Base+8, (%eax)

     movl   $0, %eax

     testb  %al, %al

     je  .L6

     movl   8(%ebp), %eax

     movl   %eax, (%esp)

     call     _ZdlPv

.L6:

     leave

     ret

     .cfi_endproc

.LFE959:

     .size   _ZN4BaseD2Ev, .-_ZN4BaseD2Ev

     .section   .text._ZN4BaseD1Ev,"axG",@progbits,_ZN4BaseD1Ev,comdat

     .align 2

     .weak _ZN4BaseD1Ev

     .type  _ZN4BaseD1Ev, @function

_ZN4BaseD1Ev:

.LFB960:

     .cfi_startproc

     .cfi_personality 0x0,__gxx_personality_v0

     pushl  %ebp

     .cfi_def_cfa_offset 8

     movl   %esp, %ebp

     .cfi_offset 5, -8

     .cfi_def_cfa_register 5

     subl    $24, %esp

     movl   8(%ebp), %eax

     movl   $_ZTV4Base+8, (%eax)

     movl   $0, %eax

     testb  %al, %al

     je  .L10

     movl   8(%ebp), %eax

     movl   %eax, (%esp)

     call     _ZdlPv

.L10:

     leave

     ret

     .cfi_endproc

.LFE960:

     .size   _ZN4BaseD1Ev, .-_ZN4BaseD1Ev

     .section   .text._ZN4BaseD0Ev,"axG",@progbits,_ZN4BaseD0Ev,comdat

     .align 2

     .weak _ZN4BaseD0Ev

     .type  _ZN4BaseD0Ev, @function

_ZN4BaseD0Ev:

.LFB961:

     .cfi_startproc

     .cfi_personality 0x0,__gxx_personality_v0

     pushl  %ebp

     .cfi_def_cfa_offset 8

     movl   %esp, %ebp

     .cfi_offset 5, -8

     .cfi_def_cfa_register 5

     subl    $24, %esp

     movl   8(%ebp), %eax

     movl   $_ZTV4Base+8, (%eax)

     movl   $1, %eax

     testb  %al, %al

     je  .L14

     movl   8(%ebp), %eax

     movl   %eax, (%esp)

     call     _ZdlPv

.L14:

     leave

     ret

     .cfi_endproc

.LFE961:

     .size   _ZN4BaseD0Ev, .-_ZN4BaseD0Ev

     .section   .text._ZN4Base5funcAEv,"axG",@progbits,_ZN4Base5funcAEv,comdat

     .align 2

     .weak _ZN4Base5funcAEv

     .type  _ZN4Base5funcAEv, @function

_ZN4Base5funcAEv:

.LFB962:

     .cfi_startproc

     .cfi_personality 0x0,__gxx_personality_v0

     pushl  %ebp

     .cfi_def_cfa_offset 8

     movl   %esp, %ebp

     .cfi_offset 5, -8

     .cfi_def_cfa_register 5

     popl    %ebp

     ret

     .cfi_endproc

.LFE962:

     .size   _ZN4Base5funcAEv, .-_ZN4Base5funcAEv

.globl _Unwind_Resume

     .section   .text._ZN7DerivedD1Ev,"axG",@progbits,_ZN7DerivedD1Ev,comdat

     .align 2

     .weak _ZN7DerivedD1Ev

     .type  _ZN7DerivedD1Ev, @function

_ZN7DerivedD1Ev:

.LFB965:

     .cfi_startproc

     .cfi_personality 0x0,__gxx_personality_v0

     .cfi_lsda 0x0,.LLSDA965

     pushl  %ebp

     .cfi_def_cfa_offset 8

     movl   %esp, %ebp

     .cfi_offset 5, -8

     .cfi_def_cfa_register 5

     pushl  %esi

     pushl  %ebx

     subl    $16, %esp

     movl   8(%ebp), %eax

     movl   $_ZTV7Derived+8, (%eax)

.LEHB0:

     .cfi_offset 3, -16

     .cfi_offset 6, -12

     call     _Z5hellov

.LEHE0:

     movl   8(%ebp), %eax

     movl   %eax, (%esp)

     call     _ZN4BaseD2Ev

     movl   $0, %eax

     testb  %al, %al

     je  .L21

     jmp    .L23

.L22:

.L19:

     movl   %edx, %ebx

     movl   %eax, %esi

     movl   8(%ebp), %eax

     movl   %eax, (%esp)

     call     _ZN4BaseD2Ev

     movl   %esi, %eax

     movl   %ebx, %edx

     movl   %eax, (%esp)

.LEHB1:

     call     _Unwind_Resume

.LEHE1:

.L23:

     movl   8(%ebp), %eax

     movl   %eax, (%esp)

     call     _ZdlPv

.L21:

     addl    $16, %esp

     popl    %ebx

     popl    %esi

     popl    %ebp

     ret

     .cfi_endproc

.LFE965:

     .size   _ZN7DerivedD1Ev, .-_ZN7DerivedD1Ev

.globl __gxx_personality_v0

     .section   .gcc_except_table,"a",@progbits

.LLSDA965:

     .byte  0xff

     .byte  0xff

     .byte  0x1

     .uleb128 .LLSDACSE965-.LLSDACSB965

.LLSDACSB965:

     .uleb128 .LEHB0-.LFB965

     .uleb128 .LEHE0-.LEHB0

     .uleb128 .L22-.LFB965

     .uleb128 0x0

     .uleb128 .LEHB1-.LFB965

     .uleb128 .LEHE1-.LEHB1

     .uleb128 0x0

     .uleb128 0x0

.LLSDACSE965:

     .section   .text._ZN7DerivedD1Ev,"axG",@progbits,_ZN7DerivedD1Ev,comdat

     .section   .text._ZN7DerivedD0Ev,"axG",@progbits,_ZN7DerivedD0Ev,comdat

     .align 2

     .weak _ZN7DerivedD0Ev

     .type  _ZN7DerivedD0Ev, @function

_ZN7DerivedD0Ev:

.LFB966:

     .cfi_startproc

     .cfi_personality 0x0,__gxx_personality_v0

     .cfi_lsda 0x0,.LLSDA966

     pushl  %ebp

     .cfi_def_cfa_offset 8

     movl   %esp, %ebp

     .cfi_offset 5, -8

     .cfi_def_cfa_register 5

     pushl  %esi

     pushl  %ebx

     subl    $16, %esp

     movl   8(%ebp), %eax

     movl   $_ZTV7Derived+8, (%eax)

.LEHB2:

     .cfi_offset 3, -16

     .cfi_offset 6, -12

     call     _Z5hellov

.LEHE2:

     movl   8(%ebp), %eax

     movl   %eax, (%esp)

     call     _ZN4BaseD2Ev

     movl   $1, %eax

     testb  %al, %al

     je  .L28

     jmp    .L30

.L29:

.L26:

     movl   %edx, %ebx

     movl   %eax, %esi

     movl   8(%ebp), %eax

     movl   %eax, (%esp)

     call     _ZN4BaseD2Ev

     movl   %esi, %eax

     movl   %ebx, %edx

     movl   %eax, (%esp)

.LEHB3:

     call     _Unwind_Resume

.LEHE3:

.L30:

     movl   8(%ebp), %eax

     movl   %eax, (%esp)

     call     _ZdlPv

.L28:

     addl    $16, %esp

     popl    %ebx

     popl    %esi

     popl    %ebp

     ret

     .cfi_endproc

.LFE966:

     .size   _ZN7DerivedD0Ev, .-_ZN7DerivedD0Ev

     .section   .gcc_except_table

.LLSDA966:

     .byte  0xff

     .byte  0xff

     .byte  0x1

     .uleb128 .LLSDACSE966-.LLSDACSB966

.LLSDACSB966:

     .uleb128 .LEHB2-.LFB966

     .uleb128 .LEHE2-.LEHB2

     .uleb128 .L29-.LFB966

     .uleb128 0x0

     .uleb128 .LEHB3-.LFB966

     .uleb128 .LEHE3-.LEHB3

     .uleb128 0x0

     .uleb128 0x0

.LLSDACSE966:

     .section   .text._ZN7DerivedD0Ev,"axG",@progbits,_ZN7DerivedD0Ev,comdat

     .section   .text._ZN7Derived5funcAEv,"axG",@progbits,_ZN7Derived5funcAEv,comdat

     .align 2

     .weak _ZN7Derived5funcAEv

     .type  _ZN7Derived5funcAEv, @function

_ZN7Derived5funcAEv:

.LFB967:

     .cfi_startproc

     .cfi_personality 0x0,__gxx_personality_v0

     pushl  %ebp

     .cfi_def_cfa_offset 8

     movl   %esp, %ebp

     .cfi_offset 5, -8

     .cfi_def_cfa_register 5

     popl    %ebp

     ret

     .cfi_endproc

.LFE967:

     .size   _ZN7Derived5funcAEv, .-_ZN7Derived5funcAEv

     .section   .text._ZN4BaseC2Ev,"axG",@progbits,_ZN4BaseC2Ev,comdat

     .align 2

     .weak _ZN4BaseC2Ev

     .type  _ZN4BaseC2Ev, @function

_ZN4BaseC2Ev:

.LFB971:

     .cfi_startproc

     .cfi_personality 0x0,__gxx_personality_v0

     pushl  %ebp

     .cfi_def_cfa_offset 8

     movl   %esp, %ebp

     .cfi_offset 5, -8

     .cfi_def_cfa_register 5

     movl   8(%ebp), %eax

     movl   $_ZTV4Base+8, (%eax)

     popl    %ebp

     ret

     .cfi_endproc

.LFE971:

     .size   _ZN4BaseC2Ev, .-_ZN4BaseC2Ev

     .section   .text._ZN7DerivedC1Ev,"axG",@progbits,_ZN7DerivedC1Ev,comdat

     .align 2

     .weak _ZN7DerivedC1Ev

     .type  _ZN7DerivedC1Ev, @function

_ZN7DerivedC1Ev:

.LFB974:

     .cfi_startproc

     .cfi_personality 0x0,__gxx_personality_v0

     pushl  %ebp

     .cfi_def_cfa_offset 8

     movl   %esp, %ebp

     .cfi_offset 5, -8

     .cfi_def_cfa_register 5

     subl    $24, %esp

     movl   8(%ebp), %eax

     movl   %eax, (%esp)

     call     _ZN4BaseC2Ev

     movl   8(%ebp), %eax

     movl   $_ZTV7Derived+8, (%eax)

     leave

     ret

     .cfi_endproc

.LFE974:

     .size   _ZN7DerivedC1Ev, .-_ZN7DerivedC1Ev

     .text

.globl main

     .type  main, @function

main:

.LFB968:

     .cfi_startproc

     .cfi_personality 0x0,__gxx_personality_v0

     pushl  %ebp

     .cfi_def_cfa_offset 8

     movl   %esp, %ebp

     .cfi_offset 5, -8

     .cfi_def_cfa_register 5

     andl    $-16, %esp

     pushl  %ebx

     subl    $44, %esp

     movl   $4, (%esp)

     .cfi_escape 0x10,0x3,0x7,0x55,0x9,0xf0,0x1a,0x9,0xfc,0x22

     call     _Znwj

     movl   %eax, %ebx

     movl   %ebx, %eax

     movl   %eax, (%esp)

     call     _ZN7DerivedC1Ev

     movl   %ebx, %eax

     movl   %eax, 28(%esp)

     cmpl   $0, 28(%esp)

     je  .L39

.L40:

.L38:

     movl   28(%esp), %eax

     movl   (%eax), %eax

     addl    $4, %eax

     movl   (%eax), %edx

     movl   28(%esp), %eax

     movl   %eax, (%esp)

     call     *%edx

.L39:

     movl   $0, %eax

     addl    $44, %esp

     popl    %ebx

     movl   %ebp, %esp

     popl    %ebp

     ret

     .cfi_endproc

.LFE968:

     .size   main, .-main

     .weak _ZTV7Derived

     .section   .rodata._ZTV7Derived,"aG",@progbits,_ZTV7Derived,comdat

     .align 8

     .type  _ZTV7Derived, @object

     .size   _ZTV7Derived, 20

_ZTV7Derived:

     .long   0

     .long   _ZTI7Derived

     .long   _ZN7DerivedD1Ev

     .long   _ZN7DerivedD0Ev

     .long   _ZN7Derived5funcAEv

     .weak _ZTV4Base

     .section   .rodata._ZTV4Base,"aG",@progbits,_ZTV4Base,comdat

     .align 8

     .type  _ZTV4Base, @object

     .size   _ZTV4Base, 20

_ZTV4Base:

     .long   0

     .long   _ZTI4Base

     .long   _ZN4BaseD1Ev

     .long   _ZN4BaseD0Ev

     .long   _ZN4Base5funcAEv

     .weak _ZTS7Derived

     .section   .rodata._ZTS7Derived,"aG",@progbits,_ZTS7Derived,comdat

     .type  _ZTS7Derived, @object

     .size   _ZTS7Derived, 9

_ZTS7Derived:

     .string "7Derived"

     .weak _ZTI7Derived

     .section   .rodata._ZTI7Derived,"aG",@progbits,_ZTI7Derived,comdat

     .align 4

     .type  _ZTI7Derived, @object

     .size   _ZTI7Derived, 12

_ZTI7Derived:

     .long   _ZTVN10__cxxabiv120__si_class_type_infoE+8

     .long   _ZTS7Derived

     .long   _ZTI4Base

     .weak _ZTS4Base

     .section   .rodata._ZTS4Base,"aG",@progbits,_ZTS4Base,comdat

     .type  _ZTS4Base, @object

     .size   _ZTS4Base, 6

_ZTS4Base:

     .string "4Base"

     .weak _ZTI4Base

     .section   .rodata._ZTI4Base,"aG",@progbits,_ZTI4Base,comdat

     .align 4

     .type  _ZTI4Base, @object

     .size   _ZTI4Base, 8

_ZTI4Base:

     .long   _ZTVN10__cxxabiv117__class_type_infoE+8

     .long   _ZTS4Base

     .text

     .type  _Z41__static_initialization_and_destruction_0ii, @function

_Z41__static_initialization_and_destruction_0ii:

.LFB983:

     .cfi_startproc

     .cfi_personality 0x0,__gxx_personality_v0

     pushl  %ebp

     .cfi_def_cfa_offset 8

     movl   %esp, %ebp

     .cfi_offset 5, -8

     .cfi_def_cfa_register 5

     subl    $24, %esp

     cmpl   $1, 8(%ebp)

     jne .L44

     cmpl   $65535, 12(%ebp)

     jne .L44

     movl   $_ZStL8__ioinit, (%esp)

     call     _ZNSt8ios_base4InitC1Ev

     movl   $_ZNSt8ios_base4InitD1Ev, %eax

     movl   $__dso_handle, 8(%esp)

     movl   $_ZStL8__ioinit, 4(%esp)

     movl   %eax, (%esp)

     call     __cxa_atexit

.L44:

     leave

     ret

     .cfi_endproc

.LFE983:

     .size     _Z41__static_initialization_and_destruction_0ii, .-_Z41__static_initialization_and_destruction_0ii

     .type  _GLOBAL__I__Z5hellov, @function

_GLOBAL__I__Z5hellov:

.LFB984:

     .cfi_startproc

     .cfi_personality 0x0,__gxx_personality_v0

     pushl  %ebp

     .cfi_def_cfa_offset 8

     movl   %esp, %ebp

     .cfi_offset 5, -8

     .cfi_def_cfa_register 5

     subl    $24, %esp

     movl   $65535, 4(%esp)

     movl   $1, (%esp)

     call     _Z41__static_initialization_and_destruction_0ii

     leave

     ret

     .cfi_endproc

.LFE984:

     .size   _GLOBAL__I__Z5hellov, .-_GLOBAL__I__Z5hellov

     .section   .ctors,"aw",@progbits

     .align 4

     .long   _GLOBAL__I__Z5hellov

     .weakref  _ZL20__gthrw_pthread_oncePiPFvvE,pthread_once

     .weakref  _ZL27__gthrw_pthread_getspecificj,pthread_getspecific

     .weakref  _ZL27__gthrw_pthread_setspecificjPKv,pthread_setspecific

     .weakref     _ZL22__gthrw_pthread_createPmPK14pthread_attr_tPFPvS3_ES3_,pthread_create

     .weakref  _ZL20__gthrw_pthread_joinmPPv,pthread_join

     .weakref  _ZL21__gthrw_pthread_equalmm,pthread_equal

     .weakref  _ZL20__gthrw_pthread_selfv,pthread_self

     .weakref  _ZL22__gthrw_pthread_detachm,pthread_detach

     .weakref  _ZL22__gthrw_pthread_cancelm,pthread_cancel

     .weakref  _ZL19__gthrw_sched_yieldv,sched_yield

     .weakref  _ZL26__gthrw_pthread_mutex_lockP15pthread_mutex_t,pthread_mutex_lock

     .weakref     _ZL29__gthrw_pthread_mutex_trylockP15pthread_mutex_t,pthread_mutex_trylock

     .weakref    _ZL31__gthrw_pthread_mutex_timedlockP15pthread_mutex_tPK8timespec,pthread_mutex_timedlock

     .weakref     _ZL28__gthrw_pthread_mutex_unlockP15pthread_mutex_t,pthread_mutex_unlock

     .weakref    _ZL26__gthrw_pthread_mutex_initP15pthread_mutex_tPK19pthread_mutexattr_t,pthread_mutex_init

     .weakref     _ZL29__gthrw_pthread_mutex_destroyP15pthread_mutex_t,pthread_mutex_destroy

     .weakref     _ZL30__gthrw_pthread_cond_broadcastP14pthread_cond_t,pthread_cond_broadcast

     .weakref  _ZL27__gthrw_pthread_cond_signalP14pthread_cond_t,pthread_cond_signal

     .weakref    _ZL25__gthrw_pthread_cond_waitP14pthread_cond_tP15pthread_mutex_t,pthread_cond_wait

     .weakref    _ZL30__gthrw_pthread_cond_timedwaitP14pthread_cond_tP15pthread_mutex_tPK8timespec,pthread_cond_timedwait

     .weakref     _ZL28__gthrw_pthread_cond_destroyP14pthread_cond_t,pthread_cond_destroy

     .weakref  _ZL26__gthrw_pthread_key_createPjPFvPvE,pthread_key_create

     .weakref  _ZL26__gthrw_pthread_key_deletej,pthread_key_delete

     .weakref     _ZL30__gthrw_pthread_mutexattr_initP19pthread_mutexattr_t,pthread_mutexattr_init

     .weakref    _ZL33__gthrw_pthread_mutexattr_settypeP19pthread_mutexattr_ti,pthread_mutexattr_settype

     .weakref    _ZL33__gthrw_pthread_mutexattr_destroyP19pthread_mutexattr_t,pthread_mutexattr_destroy

     .ident "GCC: (Ubuntu 4.4.1-4ubuntu9) 4.4.1"

     .section   .note.GNU-stack,"",@progbits

4.               虚析构函数的汇编分析

总结:在释放一个指向子类的基类指针时,如果基类具有虚析构函数,则“最底层的派生类的析构函数最先被调用,然后各个基类的析构函数被调用”。

1.               虚析构函数简介

虚析构函数的使用非常普遍。如QT中的QObject:

class Q_CORE_EXPORT QObject

{

    Q_OBJECT

    Q_PROPERTY(QString objectName READ objectName WRITE setObjectName)

    Q_DECLARE_PRIVATE(QObject)

 

public:

    Q_INVOKABLE explicit QObject(QObject *parent=0);

    virtual ~QObject();

...

}

虚析构函数的具体作用我所理解的就是避免内存泄露。

但是虚析构函数和虚函数在运行时期行为不一样,有其自己的特殊性。

2.               虚析构例子

如下面的例子:

/*Sample1*/

#include<iostream>

#include<stdlib.h>

using namespace std;

class Base

{

public:

    Base() {};

    virtual ~Base() { cout << "Destructor of Base!" << endl; }; 

 

    virtual void funcA() { cout << "funcA of Base!" << endl; };

};

 

class Derived : public Base

{

public:

    Derived() {};

    ~Derived() { cout << "Destructor of Derived!" << endl; }; 

 

    void funcA() { cout << "funcA of Derived!" << endl; };

};

 

int main()

{

Base *pderived =new Derived;

pderived->funcA();

delete pderived;

return 0;

}

运行后输出:

funcA of Derived!

Destructor of Derived!

Destructor of Base!

可以看到,虚函数只是调用了子类的虚函数。而父类和子类的虚析构函数都被调用了!

虚函数的调用通常只会调用到一个函数。而虚析构函数,则是“最底层的派生类的析构函数最先被调用,然后各个基类的析构函数被调用”。这句话援引自

《effective   C++》   14款。全文是“这个定义是必需的,因为虚析构函数工作的方式是:最底层的派生类的析构函数最先被调用,然后各个基类的析构函数被调用。这就是说,即使是抽象类,编译器也要产生对~awov的调用,所以要保证为它提供函数体。如果不这么做,链接器就会检测出来,最后还是得回去把它添上。”  

3.               虚析构函数的汇编分析

但是到目前为止,我们仅仅知道有这么一回事。但是,为什么是这么一回事?

把上面的代码修改下,输出其汇编:

/*Sample2*/

using namespace std;

class Base

{

public:

    //Base() {};

    virtual ~Base() {};// { cout << "Destructor of Base!" << endl; };

    virtual void funcA() {};// { cout << "funcA in class Base!" << endl; };

};

 

class Derived : public Base

{

public:

    //Derived() {};

    ~Derived() {}; // { cout << "Destructor of Derived!" << endl; };

    void funcA()  {}; //{ cout << "funcA in class Derived!" << endl; };

};

 

int main()

{

     Base *pderived =new Derived;

     //pderived->funcA();

     delete pderived;

    

     return 0;

}

对上述代码,针对是否使用了语句delete pderived使用g++ -S分别输出其汇编代码。

首先是没有调用delete pderived的汇编代码:

main:

.LFB968:

        .cfi_startproc

        .cfi_personality 0x0,__gxx_personality_v0

        pushl   %ebp

        .cfi_def_cfa_offset 8

        movl    %esp, %ebp

        .cfi_offset 5, -8

        .cfi_def_cfa_register 5

        andl    $-16, %esp

        pushl   %ebx

        subl    $44, %esp

        movl    $4, (%esp)

        .cfi_escape 0x10,0x3,0x7,0x55,0x9,0xf0,0x1a,0x9,0xfc,0x22

        call    _Znwj

        movl    %eax, %ebx

        movl    %ebx, %eax

        movl    %eax, (%esp)

        call    _ZN7DerivedC1Ev

        movl    %ebx, %eax

        movl    %eax, 28(%esp)

        movl    $0, %eax

.L38:

        addl    $44, %esp

        popl    %ebx

        movl    %ebp, %esp

        popl    %ebp

        ret

        .cfi_endproc

 

调用了delete pderived的汇编代码:

main:

.LFB968:

        .cfi_startproc

        .cfi_personality 0x0,__gxx_personality_v0

        pushl   %ebp

        .cfi_def_cfa_offset 8

        movl    %esp, %ebp

        .cfi_offset 5, -8

        .cfi_def_cfa_register 5

        andl    $-16, %esp

        pushl   %ebx

        subl    $44, %esp

        movl    $4, (%esp)

        .cfi_escape 0x10,0x3,0x7,0x55,0x9,0xf0,0x1a,0x9,0xfc,0x22

        call    _Znwj

        movl    %eax, %ebx

        movl    %ebx, %eax

        movl    %eax, (%esp)

        call    _ZN7DerivedC1Ev

        movl    %ebx, %eax

        movl    %eax, 28(%esp)

        cmpl    $0, 28(%esp)

        je      .L39

.L40:

.L38:

        movl    28(%esp), %eax

        movl    (%eax), %eax

        addl    $4, %eax

        movl    (%eax), %edx

        movl    28(%esp), %eax

        movl    %eax, (%esp)

        call    *%edx

.L39:

        movl    $0, %eax

        addl    $44, %esp

        popl    %ebx

        movl    %ebp, %esp

        popl    %ebp

        ret

        .cfi_endproc

注意到这两段代码有一个区别是,没有调用delete pderived的汇编代码仅仅使用了一次call指令(call   _ZN7DerivedC1Ev),而使用了两次(call    _ZN7DerivedC1Ev, call    *%edx)。

由此我们可以推断出,delete pderived的操作由call    *%edx触发的。

那么,call    *%edx到底做了些什么呢?

 

3.1           call    *%edx

先附上代码,后续补上。

 

     .file    "virtual.cpp"

     .local  _ZStL8__ioinit

     .comm _ZStL8__ioinit,1,1

     .section   .rodata

.LC0:

     .string "Destructor of Derived!"

     .text

.globl _Z5hellov

     .type  _Z5hellov, @function

_Z5hellov:

.LFB957:

     .cfi_startproc

     .cfi_personality 0x0,__gxx_personality_v0

     pushl  %ebp

     .cfi_def_cfa_offset 8

     movl   %esp, %ebp

     .cfi_offset 5, -8

     .cfi_def_cfa_register 5

     subl    $24, %esp

     movl   $.LC0, 4(%esp)

     movl   $_ZSt4cout, (%esp)

     call     _ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc

     movl   $_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_, 4(%esp)

     movl   %eax, (%esp)

     call     _ZNSolsEPFRSoS_E

     leave

     ret

     .cfi_endproc

.LFE957:

     .size   _Z5hellov, .-_Z5hellov

     .section   .text._ZN4BaseD2Ev,"axG",@progbits,_ZN4BaseD2Ev,comdat

     .align 2

     .weak _ZN4BaseD2Ev

     .type  _ZN4BaseD2Ev, @function

_ZN4BaseD2Ev:

.LFB959:

     .cfi_startproc

     .cfi_personality 0x0,__gxx_personality_v0

     pushl  %ebp

     .cfi_def_cfa_offset 8

     movl   %esp, %ebp

     .cfi_offset 5, -8

     .cfi_def_cfa_register 5

     subl    $24, %esp

     movl   8(%ebp), %eax

     movl   $_ZTV4Base+8, (%eax)

     movl   $0, %eax

     testb  %al, %al

     je  .L6

     movl   8(%ebp), %eax

     movl   %eax, (%esp)

     call     _ZdlPv

.L6:

     leave

     ret

     .cfi_endproc

.LFE959:

     .size   _ZN4BaseD2Ev, .-_ZN4BaseD2Ev

     .section   .text._ZN4BaseD1Ev,"axG",@progbits,_ZN4BaseD1Ev,comdat

     .align 2

     .weak _ZN4BaseD1Ev

     .type  _ZN4BaseD1Ev, @function

_ZN4BaseD1Ev:

.LFB960:

     .cfi_startproc

     .cfi_personality 0x0,__gxx_personality_v0

     pushl  %ebp

     .cfi_def_cfa_offset 8

     movl   %esp, %ebp

     .cfi_offset 5, -8

     .cfi_def_cfa_register 5

     subl    $24, %esp

     movl   8(%ebp), %eax

     movl   $_ZTV4Base+8, (%eax)

     movl   $0, %eax

     testb  %al, %al

     je  .L10

     movl   8(%ebp), %eax

     movl   %eax, (%esp)

     call     _ZdlPv

.L10:

     leave

     ret

     .cfi_endproc

.LFE960:

     .size   _ZN4BaseD1Ev, .-_ZN4BaseD1Ev

     .section   .text._ZN4BaseD0Ev,"axG",@progbits,_ZN4BaseD0Ev,comdat

     .align 2

     .weak _ZN4BaseD0Ev

     .type  _ZN4BaseD0Ev, @function

_ZN4BaseD0Ev:

.LFB961:

     .cfi_startproc

     .cfi_personality 0x0,__gxx_personality_v0

     pushl  %ebp

     .cfi_def_cfa_offset 8

     movl   %esp, %ebp

     .cfi_offset 5, -8

     .cfi_def_cfa_register 5

     subl    $24, %esp

     movl   8(%ebp), %eax

     movl   $_ZTV4Base+8, (%eax)

     movl   $1, %eax

     testb  %al, %al

     je  .L14

     movl   8(%ebp), %eax

     movl   %eax, (%esp)

     call     _ZdlPv

.L14:

     leave

     ret

     .cfi_endproc

.LFE961:

     .size   _ZN4BaseD0Ev, .-_ZN4BaseD0Ev

     .section   .text._ZN4Base5funcAEv,"axG",@progbits,_ZN4Base5funcAEv,comdat

     .align 2

     .weak _ZN4Base5funcAEv

     .type  _ZN4Base5funcAEv, @function

_ZN4Base5funcAEv:

.LFB962:

     .cfi_startproc

     .cfi_personality 0x0,__gxx_personality_v0

     pushl  %ebp

     .cfi_def_cfa_offset 8

     movl   %esp, %ebp

     .cfi_offset 5, -8

     .cfi_def_cfa_register 5

     popl    %ebp

     ret

     .cfi_endproc

.LFE962:

     .size   _ZN4Base5funcAEv, .-_ZN4Base5funcAEv

.globl _Unwind_Resume

     .section   .text._ZN7DerivedD1Ev,"axG",@progbits,_ZN7DerivedD1Ev,comdat

     .align 2

     .weak _ZN7DerivedD1Ev

     .type  _ZN7DerivedD1Ev, @function

_ZN7DerivedD1Ev:

.LFB965:

     .cfi_startproc

     .cfi_personality 0x0,__gxx_personality_v0

     .cfi_lsda 0x0,.LLSDA965

     pushl  %ebp

     .cfi_def_cfa_offset 8

     movl   %esp, %ebp

     .cfi_offset 5, -8

     .cfi_def_cfa_register 5

     pushl  %esi

     pushl  %ebx

     subl    $16, %esp

     movl   8(%ebp), %eax

     movl   $_ZTV7Derived+8, (%eax)

.LEHB0:

     .cfi_offset 3, -16

     .cfi_offset 6, -12

     call     _Z5hellov

.LEHE0:

     movl   8(%ebp), %eax

     movl   %eax, (%esp)

     call     _ZN4BaseD2Ev

     movl   $0, %eax

     testb  %al, %al

     je  .L21

     jmp    .L23

.L22:

.L19:

     movl   %edx, %ebx

     movl   %eax, %esi

     movl   8(%ebp), %eax

     movl   %eax, (%esp)

     call     _ZN4BaseD2Ev

     movl   %esi, %eax

     movl   %ebx, %edx

     movl   %eax, (%esp)

.LEHB1:

     call     _Unwind_Resume

.LEHE1:

.L23:

     movl   8(%ebp), %eax

     movl   %eax, (%esp)

     call     _ZdlPv

.L21:

     addl    $16, %esp

     popl    %ebx

     popl    %esi

     popl    %ebp

     ret

     .cfi_endproc

.LFE965:

     .size   _ZN7DerivedD1Ev, .-_ZN7DerivedD1Ev

.globl __gxx_personality_v0

     .section   .gcc_except_table,"a",@progbits

.LLSDA965:

     .byte  0xff

     .byte  0xff

     .byte  0x1

     .uleb128 .LLSDACSE965-.LLSDACSB965

.LLSDACSB965:

     .uleb128 .LEHB0-.LFB965

     .uleb128 .LEHE0-.LEHB0

     .uleb128 .L22-.LFB965

     .uleb128 0x0

     .uleb128 .LEHB1-.LFB965

     .uleb128 .LEHE1-.LEHB1

     .uleb128 0x0

     .uleb128 0x0

.LLSDACSE965:

     .section   .text._ZN7DerivedD1Ev,"axG",@progbits,_ZN7DerivedD1Ev,comdat

     .section   .text._ZN7DerivedD0Ev,"axG",@progbits,_ZN7DerivedD0Ev,comdat

     .align 2

     .weak _ZN7DerivedD0Ev

     .type  _ZN7DerivedD0Ev, @function

_ZN7DerivedD0Ev:

.LFB966:

     .cfi_startproc

     .cfi_personality 0x0,__gxx_personality_v0

     .cfi_lsda 0x0,.LLSDA966

     pushl  %ebp

     .cfi_def_cfa_offset 8

     movl   %esp, %ebp

     .cfi_offset 5, -8

     .cfi_def_cfa_register 5

     pushl  %esi

     pushl  %ebx

     subl    $16, %esp

     movl   8(%ebp), %eax

     movl   $_ZTV7Derived+8, (%eax)

.LEHB2:

     .cfi_offset 3, -16

     .cfi_offset 6, -12

     call     _Z5hellov

.LEHE2:

     movl   8(%ebp), %eax

     movl   %eax, (%esp)

     call     _ZN4BaseD2Ev

     movl   $1, %eax

     testb  %al, %al

     je  .L28

     jmp    .L30

.L29:

.L26:

     movl   %edx, %ebx

     movl   %eax, %esi

     movl   8(%ebp), %eax

     movl   %eax, (%esp)

     call     _ZN4BaseD2Ev

     movl   %esi, %eax

     movl   %ebx, %edx

     movl   %eax, (%esp)

.LEHB3:

     call     _Unwind_Resume

.LEHE3:

.L30:

     movl   8(%ebp), %eax

     movl   %eax, (%esp)

     call     _ZdlPv

.L28:

     addl    $16, %esp

     popl    %ebx

     popl    %esi

     popl    %ebp

     ret

     .cfi_endproc

.LFE966:

     .size   _ZN7DerivedD0Ev, .-_ZN7DerivedD0Ev

     .section   .gcc_except_table

.LLSDA966:

     .byte  0xff

     .byte  0xff

     .byte  0x1

     .uleb128 .LLSDACSE966-.LLSDACSB966

.LLSDACSB966:

     .uleb128 .LEHB2-.LFB966

     .uleb128 .LEHE2-.LEHB2

     .uleb128 .L29-.LFB966

     .uleb128 0x0

     .uleb128 .LEHB3-.LFB966

     .uleb128 .LEHE3-.LEHB3

     .uleb128 0x0

     .uleb128 0x0

.LLSDACSE966:

     .section   .text._ZN7DerivedD0Ev,"axG",@progbits,_ZN7DerivedD0Ev,comdat

     .section   .text._ZN7Derived5funcAEv,"axG",@progbits,_ZN7Derived5funcAEv,comdat

     .align 2

     .weak _ZN7Derived5funcAEv

     .type  _ZN7Derived5funcAEv, @function

_ZN7Derived5funcAEv:

.LFB967:

     .cfi_startproc

     .cfi_personality 0x0,__gxx_personality_v0

     pushl  %ebp

     .cfi_def_cfa_offset 8

     movl   %esp, %ebp

     .cfi_offset 5, -8

     .cfi_def_cfa_register 5

     popl    %ebp

     ret

     .cfi_endproc

.LFE967:

     .size   _ZN7Derived5funcAEv, .-_ZN7Derived5funcAEv

     .section   .text._ZN4BaseC2Ev,"axG",@progbits,_ZN4BaseC2Ev,comdat

     .align 2

     .weak _ZN4BaseC2Ev

     .type  _ZN4BaseC2Ev, @function

_ZN4BaseC2Ev:

.LFB971:

     .cfi_startproc

     .cfi_personality 0x0,__gxx_personality_v0

     pushl  %ebp

     .cfi_def_cfa_offset 8

     movl   %esp, %ebp

     .cfi_offset 5, -8

     .cfi_def_cfa_register 5

     movl   8(%ebp), %eax

     movl   $_ZTV4Base+8, (%eax)

     popl    %ebp

     ret

     .cfi_endproc

.LFE971:

     .size   _ZN4BaseC2Ev, .-_ZN4BaseC2Ev

     .section   .text._ZN7DerivedC1Ev,"axG",@progbits,_ZN7DerivedC1Ev,comdat

     .align 2

     .weak _ZN7DerivedC1Ev

     .type  _ZN7DerivedC1Ev, @function

_ZN7DerivedC1Ev:

.LFB974:

     .cfi_startproc

     .cfi_personality 0x0,__gxx_personality_v0

     pushl  %ebp

     .cfi_def_cfa_offset 8

     movl   %esp, %ebp

     .cfi_offset 5, -8

     .cfi_def_cfa_register 5

     subl    $24, %esp

     movl   8(%ebp), %eax

     movl   %eax, (%esp)

     call     _ZN4BaseC2Ev

     movl   8(%ebp), %eax

     movl   $_ZTV7Derived+8, (%eax)

     leave

     ret

     .cfi_endproc

.LFE974:

     .size   _ZN7DerivedC1Ev, .-_ZN7DerivedC1Ev

     .text

.globl main

     .type  main, @function

main:

.LFB968:

     .cfi_startproc

     .cfi_personality 0x0,__gxx_personality_v0

     pushl  %ebp

     .cfi_def_cfa_offset 8

     movl   %esp, %ebp

     .cfi_offset 5, -8

     .cfi_def_cfa_register 5

     andl    $-16, %esp

     pushl  %ebx

     subl    $44, %esp

     movl   $4, (%esp)

     .cfi_escape 0x10,0x3,0x7,0x55,0x9,0xf0,0x1a,0x9,0xfc,0x22

     call     _Znwj

     movl   %eax, %ebx

     movl   %ebx, %eax

     movl   %eax, (%esp)

     call     _ZN7DerivedC1Ev

     movl   %ebx, %eax

     movl   %eax, 28(%esp)

     cmpl   $0, 28(%esp)

     je  .L39

.L40:

.L38:

     movl   28(%esp), %eax

     movl   (%eax), %eax

     addl    $4, %eax

     movl   (%eax), %edx

     movl   28(%esp), %eax

     movl   %eax, (%esp)

     call     *%edx

.L39:

     movl   $0, %eax

     addl    $44, %esp

     popl    %ebx

     movl   %ebp, %esp

     popl    %ebp

     ret

     .cfi_endproc

.LFE968:

     .size   main, .-main

     .weak _ZTV7Derived

     .section   .rodata._ZTV7Derived,"aG",@progbits,_ZTV7Derived,comdat

     .align 8

     .type  _ZTV7Derived, @object

     .size   _ZTV7Derived, 20

_ZTV7Derived:

     .long   0

     .long   _ZTI7Derived

     .long   _ZN7DerivedD1Ev

     .long   _ZN7DerivedD0Ev

     .long   _ZN7Derived5funcAEv

     .weak _ZTV4Base

     .section   .rodata._ZTV4Base,"aG",@progbits,_ZTV4Base,comdat

     .align 8

     .type  _ZTV4Base, @object

     .size   _ZTV4Base, 20

_ZTV4Base:

     .long   0

     .long   _ZTI4Base

     .long   _ZN4BaseD1Ev

     .long   _ZN4BaseD0Ev

     .long   _ZN4Base5funcAEv

     .weak _ZTS7Derived

     .section   .rodata._ZTS7Derived,"aG",@progbits,_ZTS7Derived,comdat

     .type  _ZTS7Derived, @object

     .size   _ZTS7Derived, 9

_ZTS7Derived:

     .string "7Derived"

     .weak _ZTI7Derived

     .section   .rodata._ZTI7Derived,"aG",@progbits,_ZTI7Derived,comdat

     .align 4

     .type  _ZTI7Derived, @object

     .size   _ZTI7Derived, 12

_ZTI7Derived:

     .long   _ZTVN10__cxxabiv120__si_class_type_infoE+8

     .long   _ZTS7Derived

     .long   _ZTI4Base

     .weak _ZTS4Base

     .section   .rodata._ZTS4Base,"aG",@progbits,_ZTS4Base,comdat

     .type  _ZTS4Base, @object

     .size   _ZTS4Base, 6

_ZTS4Base:

     .string "4Base"

     .weak _ZTI4Base

     .section   .rodata._ZTI4Base,"aG",@progbits,_ZTI4Base,comdat

     .align 4

     .type  _ZTI4Base, @object

     .size   _ZTI4Base, 8

_ZTI4Base:

     .long   _ZTVN10__cxxabiv117__class_type_infoE+8

     .long   _ZTS4Base

     .text

     .type  _Z41__static_initialization_and_destruction_0ii, @function

_Z41__static_initialization_and_destruction_0ii:

.LFB983:

     .cfi_startproc

     .cfi_personality 0x0,__gxx_personality_v0

     pushl  %ebp

     .cfi_def_cfa_offset 8

     movl   %esp, %ebp

     .cfi_offset 5, -8

     .cfi_def_cfa_register 5

     subl    $24, %esp

     cmpl   $1, 8(%ebp)

     jne .L44

     cmpl   $65535, 12(%ebp)

     jne .L44

     movl   $_ZStL8__ioinit, (%esp)

     call     _ZNSt8ios_base4InitC1Ev

     movl   $_ZNSt8ios_base4InitD1Ev, %eax

     movl   $__dso_handle, 8(%esp)

     movl   $_ZStL8__ioinit, 4(%esp)

     movl   %eax, (%esp)

     call     __cxa_atexit

.L44:

     leave

     ret

     .cfi_endproc

.LFE983:

     .size     _Z41__static_initialization_and_destruction_0ii, .-_Z41__static_initialization_and_destruction_0ii

     .type  _GLOBAL__I__Z5hellov, @function

_GLOBAL__I__Z5hellov:

.LFB984:

     .cfi_startproc

     .cfi_personality 0x0,__gxx_personality_v0

     pushl  %ebp

     .cfi_def_cfa_offset 8

     movl   %esp, %ebp

     .cfi_offset 5, -8

     .cfi_def_cfa_register 5

     subl    $24, %esp

     movl   $65535, 4(%esp)

     movl   $1, (%esp)

     call     _Z41__static_initialization_and_destruction_0ii

     leave

     ret

     .cfi_endproc

.LFE984:

     .size   _GLOBAL__I__Z5hellov, .-_GLOBAL__I__Z5hellov

     .section   .ctors,"aw",@progbits

     .align 4

     .long   _GLOBAL__I__Z5hellov

     .weakref  _ZL20__gthrw_pthread_oncePiPFvvE,pthread_once

     .weakref  _ZL27__gthrw_pthread_getspecificj,pthread_getspecific

     .weakref  _ZL27__gthrw_pthread_setspecificjPKv,pthread_setspecific

     .weakref     _ZL22__gthrw_pthread_createPmPK14pthread_attr_tPFPvS3_ES3_,pthread_create

     .weakref  _ZL20__gthrw_pthread_joinmPPv,pthread_join

     .weakref  _ZL21__gthrw_pthread_equalmm,pthread_equal

     .weakref  _ZL20__gthrw_pthread_selfv,pthread_self

     .weakref  _ZL22__gthrw_pthread_detachm,pthread_detach

     .weakref  _ZL22__gthrw_pthread_cancelm,pthread_cancel

     .weakref  _ZL19__gthrw_sched_yieldv,sched_yield

     .weakref  _ZL26__gthrw_pthread_mutex_lockP15pthread_mutex_t,pthread_mutex_lock

     .weakref     _ZL29__gthrw_pthread_mutex_trylockP15pthread_mutex_t,pthread_mutex_trylock

     .weakref    _ZL31__gthrw_pthread_mutex_timedlockP15pthread_mutex_tPK8timespec,pthread_mutex_timedlock

     .weakref     _ZL28__gthrw_pthread_mutex_unlockP15pthread_mutex_t,pthread_mutex_unlock

     .weakref    _ZL26__gthrw_pthread_mutex_initP15pthread_mutex_tPK19pthread_mutexattr_t,pthread_mutex_init

     .weakref     _ZL29__gthrw_pthread_mutex_destroyP15pthread_mutex_t,pthread_mutex_destroy

     .weakref     _ZL30__gthrw_pthread_cond_broadcastP14pthread_cond_t,pthread_cond_broadcast

     .weakref  _ZL27__gthrw_pthread_cond_signalP14pthread_cond_t,pthread_cond_signal

     .weakref    _ZL25__gthrw_pthread_cond_waitP14pthread_cond_tP15pthread_mutex_t,pthread_cond_wait

     .weakref    _ZL30__gthrw_pthread_cond_timedwaitP14pthread_cond_tP15pthread_mutex_tPK8timespec,pthread_cond_timedwait

     .weakref     _ZL28__gthrw_pthread_cond_destroyP14pthread_cond_t,pthread_cond_destroy

     .weakref  _ZL26__gthrw_pthread_key_createPjPFvPvE,pthread_key_create

     .weakref  _ZL26__gthrw_pthread_key_deletej,pthread_key_delete

     .weakref     _ZL30__gthrw_pthread_mutexattr_initP19pthread_mutexattr_t,pthread_mutexattr_init

     .weakref    _ZL33__gthrw_pthread_mutexattr_settypeP19pthread_mutexattr_ti,pthread_mutexattr_settype

     .weakref    _ZL33__gthrw_pthread_mutexattr_destroyP19pthread_mutexattr_t,pthread_mutexattr_destroy

     .ident "GCC: (Ubuntu 4.4.1-4ubuntu9) 4.4.1"

     .section   .note.GNU-stack,"",@progbits

4.               虚析构函数的汇编分析

总结:在释放一个指向子类的基类指针时,如果基类具有虚析构函数,则“最底层的派生类的析构函数最先被调用,然后各个基类的析构函数被调用”。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值