1

c++ codes

#include <cstdio>
#include <cstdlib>

struct trivialStruct
{        

trivialStruct();
~trivialStruct();

int *a;
float *b;
float *c;

};

trivialStruct::trivialStruct() : a((int*)malloc(sizeof(int))), b((float*)malloc(sizeof(float))), c((float*)malloc(sizeof(float)))
{
  *a = 100;
  *b = 200;
  *c = 300;
}

trivialStruct::~trivialStruct()
{
  free(a);
  free(b);
  free(c);

  a = nullptr;
  b = nullptr;
  c = nullptr;
}

int main()
{
  trivialStruct A;
  printf("%d, %f, %f", *A.a, *A.b, *A.c);

  return 0;
}

assembly

.section    __TEXT,__text,regular,pure_instructions
    .globl  __ZN13trivialStructC1Ev
    .align  4, 0x90
__ZN13trivialStructC1Ev:                ## @_ZN13trivialStructC1Ev
    .cfi_startproc
## BB#0:                                ## %entry
    push    RBP
Ltmp3:
    .cfi_def_cfa_offset 16
Ltmp4:
    .cfi_offset rbp, -16
    mov RBP, RSP
Ltmp5:
    .cfi_def_cfa_register rbp
    push    R15
    push    R14
    push    RBX
    push    RAX
Ltmp6:
    .cfi_offset rbx, -40
Ltmp7:
    .cfi_offset r14, -32
Ltmp8:
    .cfi_offset r15, -24
    mov RBX, RDI
    mov EDI, 4
    call    _malloc
    mov R14, RAX
    mov QWORD PTR [RBX], R14
    mov EDI, 4
    call    _malloc
    mov R15, RAX
    mov QWORD PTR [RBX + 8], R15
    mov EDI, 4
    call    _malloc
    mov QWORD PTR [RBX + 16], RAX
    mov DWORD PTR [R14], 100
    mov DWORD PTR [R15], 1128792064
    mov DWORD PTR [RAX], 1133903872
    add RSP, 8
    pop RBX
    pop R14
    pop R15
    pop RBP
    ret
    .cfi_endproc

    .globl  __ZN13trivialStructC2Ev
    .align  4, 0x90
__ZN13trivialStructC2Ev:                ## @_ZN13trivialStructC2Ev
    .cfi_startproc
## BB#0:                                ## %entry
    push    RBP
Ltmp12:
    .cfi_def_cfa_offset 16
Ltmp13:
    .cfi_offset rbp, -16
    mov RBP, RSP
Ltmp14:
    .cfi_def_cfa_register rbp
    push    R15
    push    R14
    push    RBX
    push    RAX
Ltmp15:
    .cfi_offset rbx, -40
Ltmp16:
    .cfi_offset r14, -32
Ltmp17:
    .cfi_offset r15, -24
    mov RBX, RDI
    mov EDI, 4
    call    _malloc
    mov R14, RAX
    mov QWORD PTR [RBX], R14
    mov EDI, 4
    call    _malloc
    mov R15, RAX
    mov QWORD PTR [RBX + 8], R15
    mov EDI, 4
    call    _malloc
    mov QWORD PTR [RBX + 16], RAX
    mov DWORD PTR [R14], 100
    mov DWORD PTR [R15], 1128792064
    mov DWORD PTR [RAX], 1133903872
    add RSP, 8
    pop RBX
    pop R14
    pop R15
    pop RBP
    ret
    .cfi_endproc

    .globl  __ZN13trivialStructD1Ev
    .align  4, 0x90
__ZN13trivialStructD1Ev:                ## @_ZN13trivialStructD1Ev
    .cfi_startproc
## BB#0:                                ## %entry
    push    RBP
Ltmp21:
    .cfi_def_cfa_offset 16
Ltmp22:
    .cfi_offset rbp, -16
    mov RBP, RSP
Ltmp23:
    .cfi_def_cfa_register rbp
    push    RBX
    push    RAX
Ltmp24:
    .cfi_offset rbx, -24
    mov RBX, RDI
    mov RDI, QWORD PTR [RBX]
    call    _free
    mov RDI, QWORD PTR [RBX + 8]
    call    _free
    mov RDI, QWORD PTR [RBX + 16]
    call    _free
    mov QWORD PTR [RBX + 16], 0
    mov QWORD PTR [RBX + 8], 0
    mov QWORD PTR [RBX], 0
    add RSP, 8
    pop RBX
    pop RBP
    ret
    .cfi_endproc

    .globl  __ZN13trivialStructD2Ev
    .align  4, 0x90
__ZN13trivialStructD2Ev:                ## @_ZN13trivialStructD2Ev
    .cfi_startproc
## BB#0:                                ## %entry
    push    RBP
Ltmp28:
    .cfi_def_cfa_offset 16
Ltmp29:
    .cfi_offset rbp, -16
    mov RBP, RSP
Ltmp30:
    .cfi_def_cfa_register rbp
    push    RBX
    push    RAX
Ltmp31:
    .cfi_offset rbx, -24
    mov RBX, RDI
    mov RDI, QWORD PTR [RBX]
    call    _free
    mov RDI, QWORD PTR [RBX + 8]
    call    _free
    mov RDI, QWORD PTR [RBX + 16]
    call    _free
    mov QWORD PTR [RBX + 16], 0
    mov QWORD PTR [RBX + 8], 0
    mov QWORD PTR [RBX], 0
    add RSP, 8
    pop RBX
    pop RBP
    ret
    .cfi_endproc

    .section    __TEXT,__literal8,8byte_literals
    .align  3
LCPI4_0:
    .quad   4641240890982006784     ## double 200
LCPI4_1:
    .quad   4643985272004935680     ## double 300
    .section    __TEXT,__text,regular,pure_instructions
    .globl  _main
    .align  4, 0x90
_main:                                  ## @main
    .cfi_startproc
## BB#0:                                ## %entry
    push    RBP
Ltmp34:
    .cfi_def_cfa_offset 16
Ltmp35:
    .cfi_offset rbp, -16
    mov RBP, RSP
Ltmp36:
    .cfi_def_cfa_register rbp
    lea RDI, QWORD PTR [RIP + L_.str]
    movsd   XMM0, QWORD PTR [RIP + LCPI4_0]
    movsd   XMM1, QWORD PTR [RIP + LCPI4_1]
    mov ESI, 100
    mov AL, 2
    call    _printf
    xor EAX, EAX
    pop RBP
    ret
    .cfi_endproc

    .section    __TEXT,__cstring,cstring_literals
L_.str:                                 ## @.str
    .asciz   "%d, %f, %f"


.subsections_via_symbols

command clang++ -S -O2 -std=c++11 -mllvm --x86-asm-syntax=intel -fno-exceptions main.cpp

As you can see, there are two part of codes are same(constructor and destructor)

  1. __ZN13trivialStructC1Ev: ## @_ZN13trivialStructC1Ev
  2. __ZN13trivialStructC2Ev: ## @_ZN13trivialStructC2Ev
  3. __ZN13trivialStructD1Ev: ## @_ZN13trivialStructD1Ev
  4. __ZN13trivialStructD2Ev: ## @_ZN13trivialStructD2Ev

I have no idea why the compiler generate two part of codes but not just one? I am no familiar with assembly, but looks like this just make the codes become fatter(and maybe slower).

StereoMatching
  • 4,971
  • 6
  • 38
  • 70
  • 1
    Try to optimize code for size (pass `-Os` to g++). Also, less code is not always better - branches can be very expensive. – Nemanja Boric Nov 25 '13 at 18:40
  • 1
    Note that the code won't be *slower*. If the constructors are not used, the linker can potentially remove the symbols (read your linker's documentation) and even if they are not removed, they will take some space in memory, but will never be evaluated (i.e. won't cause other code to be evicted from the cache). – David Rodríguez - dribeas Nov 25 '13 at 18:55

1 Answers1

3

This is part of the ABI for your platform, and escapes the standard. Both constructors and destructors can generate multiple symbols in the binary. For example, the Itanium C++ABI will generate up to 3 constructors/destructors:

  • complete object constructor
  • base object constructor
  • complete object allocating constructor
  • deleting destructor
  • complete object destructor
  • base object destructor

The different symbols take on slightly different responsibilities as the implementation might need to do different things depending on how the object is being created/destroyed. In your particular case, the code is simple enough that all constructors might generate exactly the same code, but they need to be there to comply with the ABI, and the ABI has them to enable more complex use cases.

For example, a complete object constructor will initialize virtual bases, while the base object constructor will skip this part of construction. If there is multiple/virtual inheritance and virtual functions, the vptr in the complete object may have to jump through different sets of intermediate tables depending on how this subobject is being instantiated.

If you want an explanation other than the ABI mandates, you should take a look at the documentation for your particular ABI. You can also take a look at Inside the C++ object model that even if old, contains a good description of what the problems to solve are and some of the solutions provided.

David Rodríguez - dribeas
  • 204,818
  • 23
  • 294
  • 489