Address-ordering of members of a class / struct
Asked Answered
D

1

7

The C++23 draft mandates that later non-static data members of a structure or class must have higher addresses. AFAIK earlier standards require this also partitially but there are rules when the compiler is allowed to reorder these data members. Can anyone here tell me which rules apply exactly when ?

Duel answered 15/5, 2022 at 18:58 Comment(1)
No rules per se. Ordering can change between public, private, and protected sections. Don't know any compiler that does this though.Charlottcharlotta
B
6

From latest C++23 draft:

[expr.rel]

The result of comparing unequal pointers to objects is defined in terms of a partial order consistent with the following rules:

  • If two pointers point to different non-static data members of the same object, or to subobjects of such members, recursively, the pointer to the later declared member is required to compare greater provided neither member is a subobject of zero size and their class is not a union.

The allocation order of non-static members is a necessary consequence of this rule. The rule is referred by a note:

[class.mem.general]

[Note 8: Non-variant non-static data members of non-zero size ([intro.object]) are allocated so that later members have higher addresses within a class object ([expr.rel]).


In C++11-20, prior to the proposal P1847, the rule was:

  • If two pointers point to different non-static data members of the same object, or to subobjects of such members, recursively, the pointer to the later declared member is required to compare greater provided the two members have the same access control ([class.access]), neither member is a subobject of zero size, and their class is not a union.
  • Otherwise, neither pointer is required to compare greater than the other

Pre C++23, compilers are allowed to re-order members with differing access control. Example:

struct s {
    int a;
protected:
    int b;
};

s ab;
// value of c is implementation dependent in C++20
// value of c is true in C++23
bool c = &ab.a < &ab.b;

Major compilers haven't actually used any other than declaration order.

C++03 was even more relaxed, although subtly:

[class.mem]

Nonstatic data members of a (non-union) class declared without an intervening access-specifier are allocated so that later members have higher addresses within a class object. The order of allocation of non-static data members separated by an access-specifier is unspecified (11.1).


[expr.rel]

  • If two pointers point to non-static data members of the same object, or to subobjects or array elements of such members, recursively, the pointer to the later declared member compares greater provided the two members are not separated by an access-specifier label (11.1) and provided their class is not a union.
  • If two pointers point to non-static data members of the same object separated by an access-specifier label (11.1) the result is unspecified.
Bush answered 15/5, 2022 at 19:26 Comment(5)
It's a shame. This breaks space optimization in struct A { char c; int x; }; class B : A { char d; }; The d can now no longer be tucked into the padding.Funderburk
@GoswinvonBrederlow True, but did that ever happen or is this just c++23 recognizing existing practice? If the latter, then it just increases clarity for us coders. As a coder I'd recognize the common pattern and use this struct A { int x; char c; };Charlottcharlotta
I know sysv ABI puts members into the padding at the end of a base class if it isn't an aggregate. But that would still be allowed with the new rules. (Windows ABI doesn't)Funderburk
@GoswinvonBrederlow Since relation comparison is specified only for pointers of similar (~same) type, nothing prohibits from "moving" NSDMs through ones of different type. Except that comparison caring about pointer type, not value, may be defective.Esque
@LanguageLawyer That could be complex to decide as it's not just different type but the two NSDMs must not have any common subtypes recursively. For two structs containing a char the addresses of the chars can be compared according to the above rules.Funderburk

© 2022 - 2024 — McMap. All rights reserved.