Why are unions which have members with differing access control not standard-layout?

100 views
Skip to first unread message

omnipote...@gmail.com

unread,
Apr 15, 2015, 1:06:10 PM4/15/15
to std-dis...@isocpp.org
From §9.0

7. A class S is a standard-layout class if it:
(7.3) has the same access control (Clause 11) for all non-static data members,

8 A standard-layout struct is a standard-layout class defined with the class-key struct or the class-key class. A standard-layout union is a standard-layout class defined with the class-key union.

As far as I can tell, §9.0.7.3 exists because of §9.2.13

13 Nonstatic data members of a (non-union) class with the same access control (Clause 11) are allocated so that later members have higher addresses within a class object. The order of allocation of non-static data members with different access control is unspecified (Clause 11). Implementation alignment requirements might cause two adjacent members not to be allocated immediately after each other; so might requirements for space for managing virtual functions (10.3) and virtual base classes (10.1).

However, this does not seem to apply to unions, as all (non-static data) members of a union have the same address.  Is this an oversight in the standard?  Or is there some compelling reason why that I'm not seeing?

Ville Voutilainen

unread,
Apr 15, 2015, 1:13:15 PM4/15/15
to std-dis...@isocpp.org
What sort of an oversight? As far as I understand, there are
historical reasons for
it - there were implementations that didn't allocate members with
differing access
sequentially for classes, so perhaps that issue never arose with unions.

Michael Reilly

unread,
Apr 15, 2015, 1:31:44 PM4/15/15
to std-dis...@isocpp.org
The reason why I think it's an oversight is because all non-static data
members of a union share the same address, which means you don't have to
worry about indeterminate ordering due to differing access control
(which is why the restriction exists in the first place?)

As far as history goes on this, standard-layout classes were introduced
by N2342
(http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2342.htm) to
resolve Core Issue 568
(http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2029.html#568).

I assume that Mr. Dawes overlooked the possibility of adding "or is a
union type class" to the end of 9.0.7.3 when he added that line.

I had attempted to contact him about 2 weeks ago. But I assume my
e-mail was either discarded or lost in the shuffle, as I understand he
is very busy.

Thanks,
Michael

Thiago Macieira

unread,
Apr 15, 2015, 11:28:24 PM4/15/15
to std-dis...@isocpp.org
On Wednesday 15 April 2015 13:31:42 Michael Reilly wrote:
> The reason why I think it's an oversight is because all non-static data
> members of a union share the same address, which means you don't have to
> worry about indeterminate ordering due to differing access control
> (which is why the restriction exists in the first place?)
>
> As far as history goes on this, standard-layout classes were introduced
> by N2342
> (http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2342.htm) to
> resolve Core Issue 568
> (http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2029.html#568).
>
> I assume that Mr. Dawes overlooked the possibility of adding "or is a
> union type class" to the end of 9.0.7.3 when he added that line.

That would allow a union with non-static members with differing access to be
POD (standard layout + trivial). Did C++98 allow that?

--
Thiago Macieira - thiago (AT) macieira.info - thiago (AT) kde.org
Software Architect - Intel Open Source Technology Center
PGP/GPG: 0x6EF45358; fingerprint:
E067 918B B660 DBD1 105C 966C 33F5 F005 6EF4 5358

omnipote...@gmail.com

unread,
Apr 16, 2015, 12:41:34 AM4/16/15
to std-dis...@isocpp.org

It seems that the C++98 standard carried this text in 9.0.4:

 POD-struct is an aggregate class that has no non-static data members of type non-POD-struct, non-POD-union (or array of such types) or reference, and has no user-declared copy assignment operator and no user-declared destructor. Similarly, a POD-union is an aggregate union that has no non-static data members of type non-POD-struct, non-POD-union (or array of such types) or reference, and has no user-declared copy assignment operator and no user-declared destructor. A POD class is a class that is either a POD-struct or a POD-union.

Where an aggregate class is defined in 8.5.1:

An aggregate is an array or a class (clause 9) with no user-declared constructors (12.1), no private or protected non-static data members (clause 11), no base classes (clause 10), and no virtual functions (10.3).

So no. But remember that the purpose of N2342 was to fix the fact that this definition was too restrictive.  For instance, a union with all private members (which is POD now) would not have been POD in C++98.

Thiago Macieira

unread,
Apr 16, 2015, 3:11:59 AM4/16/15
to std-dis...@isocpp.org
On Wednesday 15 April 2015 21:41:34 omnipote...@gmail.com wrote:
> > That would allow a union with non-static members with differing access to
> > be
> > POD (standard layout + trivial). Did C++98 allow that?
>
> It seems that the C++98 standard carried this text in 9.0.4:
>
> POD-struct is an aggregate class that has no non-static data members of
> type non-POD-struct, non-POD-union (or array of such types) or reference,
> and has no user-declared copy assignment operator and no user-declared
> destructor. Similarly, a POD-union is an aggregate union that has no
> non-static data members of type non-POD-struct, non-POD-union (or array of
> such types) or reference, and has no user-declared copy assignment operator
> and no user-declared destructor. A POD class is a class that is either a
> POD-struct or a POD-union.
>
> Where an aggregate class is defined in 8.5.1:
>
> An aggregate is an array or a class (clause 9) with no user-declared
> constructors (12.1), no private or protected non-static data members
> (clause 11), no base classes (clause 10), and no virtual functions (10.3).
>
> So no. But remember that the purpose of N2342 was to fix the fact that this
> definition was too restrictive. For instance, a union with all private
> members (which is POD now) would not have been POD in C++98.

Right. It relaxed the requirement but still left the same rules for all types
of aggregates, whether they be unions or not.

That said, I can't think of a good reason why different accesses in a union
should cause it to change layout, given the requirement that all members have
the same address. If it doesn't change the layout, it stands to reason it's
the same layout as the standard layout.

A far-fetched scenario would be that the union has extra bookkeeping because
of protected or private members, but I can't fathom a reason where this would
be necessary.

Myriachan

unread,
May 4, 2015, 11:13:16 PM5/4/15
to std-dis...@isocpp.org
On Thursday, April 16, 2015 at 12:11:59 AM UTC-7, Thiago Macieira wrote:
Right. It relaxed the requirement but still left the same rules for all types
of aggregates, whether they be unions or not.

That said, I can't think of a good reason why different accesses in a union
should cause it to change layout, given the requirement that all members have
the same address. If it doesn't change the layout, it stands to reason it's
the same layout as the standard layout.

A far-fetched scenario would be that the union has extra bookkeeping because
of protected or private members, but I can't fathom a reason where this would
be necessary.


I think that such a scenario is beyond just far-fetched, but rather actually non-compliant by the same argument as why I believe trivially-copyable types ought to be considered compatible with offsetof.

However, the possibility exists, though is far-fetched as you say, that a compiler could assign a nonzero offset to the members of such a union.  I believe that only in the case of a standard-layout union is the compiler required to ensure that the union and its members are at the same address.

Melissa

David Rodríguez Ibeas

unread,
May 8, 2015, 4:48:16 AM5/8/15
to std-dis...@isocpp.org
On Tue, May 5, 2015 at 4:13 AM, Myriachan <myri...@gmail.com> wrote:
However, the possibility exists, though is far-fetched as you say, that a compiler could assign a nonzero offset to the members of such a union.

I don't think this is the case. The standard requires that all members (standard-layout or not) are allocated as if they where the sole member of a struct (no mention to access specifiers here).  While this does not guarantee that in the particular case of a non-standard-layout member a compiler may be allowed to offset non-public members by some amount... but that does not seem the intent of the language. The access specifier of a class with a single member does not affect whether that type is standard-layout or not --it will/will not be depending on whether the member itself is standard-layout.

Yes, once the member is not standard-layout the compiler could do anything at all... but the case is so restricted that I cannot see any rationale for that behavior.

David
Reply all
Reply to author
Forward
0 new messages