我们可以借助binutils工具集中的objdump来印证前面所述内容。代码6示例了class1.o目标文件的反汇编代码。读者不需要细读其中的汇编代码,但请留意位置为4a和66的两个函数。前者是class1.cpp文件中s_class1变量的析构函数,后者则是对应的构造函数。

    $ g++ -c –g class1.cpp
    $ objdump -S -d --demangle=gnu-v3 class1.o
     
    class1.o:     file format pe-i386
     
     
    Disassembly of section .text:
     
    ……内容有删减……
    0000004a <global destructors keyed to class1.cpp>:
      4a:   55                      push   %ebp
      4b:   89 e5                   mov    %esp,%ebp
      4d:   83 ec 08                sub    $0x8,%esp
      50:   c7 44 24 04 ff ff 00    movl   $0xffff,0x4(%esp)
      57:   00
      58:   c7 04 24 00 00 00 00    movl   $0x0,(%esp)
      5f:   e8 9c ff ff ff          call   0
      64:   c9                      leave
      65:   c3                      ret
     
    00000066 <global constructors keyed to class1.cpp>:
      66:   55                      push   %ebp
      67:   89 e5                   mov    %esp,%ebp
      69:   83 ec 08                sub    $0x8,%esp
      6c:   c7 44 24 04 ff ff 00    movl   $0xffff,0x4(%esp)
      73:   00
      74:   c7 04 24 01 00 00 00    movl   $0x1,(%esp)
      7b:   e8 80 ff ff ff          call   0
      80:   c9                      leave
      81:   c3                      ret
      82:   90                      nop
      83:   90                      nop

代码6

  代码7示例了如何通过objdump工具查看class1.o文件中.ctors和.dtors段中的内容。从内容中可以看到存在前面提到的4a和66两个值,而这两个值会终被ld链接器分别放入__CTOR_LIST__和__DTOR_LIST__数组中。

    $ objdump -s -j .ctors class1.o
     
    class1.o:     file format pe-i386
     
    Contents of section .ctors:
     0000 66000000                             f...
    $ objdump -s -j .dtors class1.o
     
    class1.o:     file format pe-i386
     
    Contents of section .dtors:
     0000 4a000000                             J...

代码7

  了解了编译器是如何处理全局类对象的构造和析构函数后,我们不难理解开始提到的有趣现象了。这是因为文件编译时的位置顺序会终影响各类全局变量的构造与析构函数在__CTOR_LIST__和__DTOR_LIST__数组中的先后顺序。

  了解这一内容有什么意义呢?这有助于我们掌握如何在C++中正确实现singleton设计模式,这一话题让我们留到另一篇博文中探讨。