Virtual tables on anonymous classes
Asked Answered
B

3

12

I have something similar to this in my code:

#include <iostream>
#include <cstdlib>

struct Base
{
  virtual int Virtual() = 0;
};

struct Child
{
  struct : public Base
  {
    virtual int Virtual() { return 1; }
  } First;

  struct : public Base
  {
    virtual int Virtual() { return 2; }
  } Second;
};

int main()
{
  Child child;
  printf("ble: %i\n", ((Base*)&child.First)->Virtual());
  printf("ble: %i\n", ((Base*)&child.Second)->Virtual());

  system("PAUSE");
  return 0;
}

I'd expect this to give this output:

ble: 1
ble: 2

and it does so, when compiled under GCC (3.4.5 I believe).

Compiling and running this under Visual Studio 2008 however, gives this:

ble: 2
ble: 2

What is interesting, is that if I give the Base-derived structs names (struct s1 : public Base), it works correctly.

Which behavior, if any, is correct? Is VS just being prissy, or is it adhering to the standard? Am I missing something vital here?

Briolette answered 17/1, 2010 at 19:45 Comment(9)
Works as expect in gcc. Though to be blunt I was it expecting it not to compile.Protrusion
VS adhering to the standard? Ha ha ha ha ha...Felt
Hey, VC++ has gotten much better at that.Recount
VS is pretty good at sticking to the standard. Off-hand I can only think of a couple of features it doesn't support. Two-phase name lookup, exception specifications and the export keyword. And the two last ones are generally considered Bad Ideas anyway. (Last I checked, the plan for C++0x was to deprecate exception specifications, and most compilers pretend that export never existed)Kenwood
In most cases where VC breaks from the standard today its for historic reasons and would break large existing code-bases if they changed the defaults... notably the extensions that were neccessary for COM.Celt
@gf interesting, I would be interested in any technical documentation outlining these, got any references ?Holster
VC6 was a joke for conformance (a reputation that seems to have carried forward to today in some minds) - but be fair, it was released in 1998, the same year the standard was ratified. VC10 (and VC9, for that matter) is one of most conformant compilers on the market. And @gf, what extensions are you referring to?Cynar
Still broken in VS2013, many years later...Kimmel
It is, however, fixed in Visual Studio 2015.Briolette
P
2

It is visible how MSVC is getting it wrong from the debugging symbols. It generates temporary names for the anonymous structs, respectively Child::<unnamed-type-First> and Child::<unnamed-type-Second>. There is however only one vtable, it is named Child::<unnamed-tag>::'vftable' and both constructors use it. The different name for the vtable surely is part of the bug.

There are several bugs reported at connection.microsoft.com that are related to anonymous types, none of which ever made it to "must-fix" status. Not the one you found though, afaict. Maybe the workaround is just too simple.

Polemoniaceous answered 17/1, 2010 at 23:0 Comment(0)
Y
7

It appears this is a bug in VS 2008, possibly because it overwrites or ignores the vtable for the first unnamed class in favor of the vtable for the second since the internal names are identical. (When you name one explicitly, the internal names for the vtables are no longer identical.)

As far as I can tell from the standard, this should work as you expect and gcc is right.

Yearly answered 17/1, 2010 at 20:12 Comment(1)
(+1) well written explanation.Holster
P
2

It is visible how MSVC is getting it wrong from the debugging symbols. It generates temporary names for the anonymous structs, respectively Child::<unnamed-type-First> and Child::<unnamed-type-Second>. There is however only one vtable, it is named Child::<unnamed-tag>::'vftable' and both constructors use it. The different name for the vtable surely is part of the bug.

There are several bugs reported at connection.microsoft.com that are related to anonymous types, none of which ever made it to "must-fix" status. Not the one you found though, afaict. Maybe the workaround is just too simple.

Polemoniaceous answered 17/1, 2010 at 23:0 Comment(0)
C
1

I can confirm this is a known bug in the VC compiler (and it repos in VC10); the two anonymous classes are incorrectly sharing a vtable.

Anonymous structs are not part of the C++ standard.

Edit: Anonymous structs are kind of an ambiguous term. It can mean two things:

class outer
{
public:
    struct {
        int a;
        int b;
    } m_a; // 1

    struct {
        int c;
    };     // 2

    union {
        int d;
        int e;
    };     // 3
};

1 is what is going on here, a better name than anonymous struct would be "unnamed struct". The struct type itself doesn't have a name, but the object does (m_a).

2 is also known as an anonymous struct, and isn't legal C++. There is no object name, and the idea is you could access the field 'c' directly on objects of type outer. This compiles only because of a compiler extension in Visual Studio (will fail under /Za)

3 Anonymous unions, by contrast, are legal C++.

I confused the two, because here we're calling #1 an "anonymous struct", and wires in my brain crossed with #2.

Cynar answered 18/1, 2010 at 0:29 Comment(8)
Unnamed classes are standard C++ and are sometimes called "anonymous" instead of "unnamed".Yearly
@Roger, What I said is correct. I said anonymous structs ; not anonymous classes. Anonymous classes are part of the C++ standard. Anonymous structs are a C thing, and not part of C++ (although they are widely supported vendor extension, including VC).Cynar
"A structure is a class defined with the class-key struct ..." [9/4] Structs are classes.Yearly
See open-std.org/jtc1/sc22/wg14/www/docs/n1289.htm. This is the C++ Standards Committee statement on the topic. Note the part which says "ANSI C++ anonymous structs: NO". Google the topic and you'll see a lot of discussion around it, and the consensus is they are not part of the standard.Cynar
And from MSDN: msdn.microsoft.com/en-us/library/z2cx9y4f.aspx, "A Microsoft C extension...C++ does not allow anonymous structures."Cynar
The msdn link is talking about something completely different and unrelated from what is used in this question, which may be the source of your confusion. And rereading n1289, I can see it's talking about something other than unnamed classes too. In the OP's code, it is the class names which are absent, not the object names.Yearly
@Roger, you're right - I am confused. I keep talking about anonymous structs (and give links talking about them), but here it's an unnamed struct, not an anonymous struct! ThanksCynar
@Potatoswatter, @Roger, I updated the answer to try to give this comment thread some contextCynar

© 2022 - 2024 — McMap. All rights reserved.