Today I discovered a rather interesting thing about g++ or nm ... constructor definitions seem to have two entries in the libraries.
I have a thing.hpp header:
class Thing { Thing(); Thing(int x); void foo(); };
And thing.cpp :
#include "thing.hpp" Thing::Thing() { } Thing::Thing(int x) { } void Thing::foo() { }
I will compile this with:
g++ thing.cpp -c -o libthing.a
Then I ran nm on it:
%> nm -gC libthing.a 0000000000000030 T Thing::foo() 0000000000000022 T Thing::Thing(int) 000000000000000a T Thing::Thing() 0000000000000014 T Thing::Thing(int) 0000000000000000 T Thing::Thing() U __gxx_personality_v0
As you can see, both constructors for Thing are listed with two entries in the generated static library. My g++ is 4.4.3, but the same behavior happens in clang , so this is not just a gcc problem.
This does not cause any obvious problems, but I was wondering:
- Why are certain constructors listed twice?
- Why does this not cause a problem with "multiple __ character definitions"?
EDIT : for Carl, output without argument C :
%> nm -g libthing.a 0000000000000030 T _ZN5Thing3fooEv 0000000000000022 T _ZN5ThingC1Ei 000000000000000a T _ZN5ThingC1Ev 0000000000000014 T _ZN5ThingC2Ei 0000000000000000 T _ZN5ThingC2Ev U __gxx_personality_v0
As you can see ... the same function generates several characters, which is still pretty curious.
And while we're on it, here is the generated assembly section:
.globl _ZN5ThingC2Ev .type _ZN5ThingC2Ev, @function _ZN5ThingC2Ev: .LFB1: .cfi_startproc .cfi_personality 0x3,__gxx_personality_v0 pushq %rbp .cfi_def_cfa_offset 16 movq %rsp, %rbp .cfi_offset 6, -16 .cfi_def_cfa_register 6 movq %rdi, -8(%rbp) leave ret .cfi_endproc .LFE1: .size _ZN5ThingC2Ev, .-_ZN5ThingC2Ev .align 2 .globl _ZN5ThingC1Ev .type _ZN5ThingC1Ev, @function _ZN5ThingC1Ev: .LFB2: .cfi_startproc .cfi_personality 0x3,__gxx_personality_v0 pushq %rbp .cfi_def_cfa_offset 16 movq %rsp, %rbp .cfi_offset 6, -16 .cfi_def_cfa_register 6 movq %rdi, -8(%rbp) leave ret .cfi_endproc
So, the generated code ... well ... the same.
EDIT . To find out which constructor is actually called, I changed Thing::foo() to this:
void Thing::foo() { Thing t; }
Generated assembly:
.globl _ZN5Thing3fooEv .type _ZN5Thing3fooEv, @function _ZN5Thing3fooEv: .LFB550: .cfi_startproc .cfi_personality 0x3,__gxx_personality_v0 pushq %rbp .cfi_def_cfa_offset 16 movq %rsp, %rbp .cfi_offset 6, -16 .cfi_def_cfa_register 6 subq $48, %rsp movq %rdi, -40(%rbp) leaq -32(%rbp), %rax movq %rax, %rdi call _ZN5ThingC1Ev leaq -32(%rbp), %rax movq %rax, %rdi call _ZN5ThingD1Ev leave ret .cfi_endproc
Thus, it calls the full constructor of the object.