Dual emission of constructor symbols

We’ll start by declaring that GCC follows the Itanium C++ ABI.


According to the ABI, the mangled name for your Thing::foo() is easily parsed:

_Z     | N      | 5Thing  | 3foo | E          | v
prefix | nested | `Thing` | `foo`| end nested | parameters: `void`

You can read the constructor names similarly, as below. Notice how the constructor “name” isn’t given, but instead a C clause:

_Z     | N      | 5Thing  | C1          | E          | i
prefix | nested | `Thing` | Constructor | end nested | parameters: `int`

But what’s this C1? Your duplicate has C2. What does this mean?

Well, this is quite simple too:

  <ctor-dtor-name> ::= C1   # complete object constructor
                   ::= C2   # base object constructor
                   ::= C3   # complete object allocating constructor
                   ::= D0   # deleting destructor
                   ::= D1   # complete object destructor
                   ::= D2   # base object destructor

Wait, why is this simple? This class has no base. Why does it have a “complete object constructor” and a “base object constructor” for each?

  • This Q&A implies to me that this is simply a by-product of polymorphism support, even though it’s not actually required in this case.

  • Note that c++filt used to include this information in its demangled output, but doesn’t any more.

  • This forum post asks the same question, and the only response doesn’t do any better at answering it, except for the implication that GCC could avoid emitting two constructors when polymorphism is not involved, and that this behaviour ought to be improved in the future.

  • This newsgroup posting describes a problem with setting breakpoints in constructors due to this dual-emission. It’s stated again that the root of the issue is support for polymorphism.

In fact, this is listed as a GCC “known issue”:

G++ emits two copies of constructors and destructors.

In general there are three types of constructors (and
destructors).

  • The complete object constructor/destructor.
  • The base object constructor/destructor.
  • The allocating constructor/deallocating destructor.

The first two are different, when virtual base classes are
involved.


The meaning of these different constructors seems to be as follows:

  • The “complete object constructor”. It additionally constructs virtual base classes.

  • The “base object constructor”. It creates the object itself, as well as data members and non-virtual base classes.

  • The “allocating object constructor”. It does everything the complete object constructor does, plus it calls operator new to actually allocate the memory… but apparently this is not usually seen.

If you have no virtual base classes, [the first two] are are
identical; GCC will, on sufficient optimization levels, actually alias
the symbols to the same code for both.

Leave a Comment