4

Lets say I have two types A and B.

Then I make this type

struct Pair{
    A a;
    B b;
};

Now I have a function such as this.

void function(Pair& pair);

And lets assume that function will only ever use the a part of the pair.

Then is it undefined behavior to use and call the function in this way?

A a;
function(reinterpret_cast<Pair&>(a));

I know that a compiler may insert padding bytes after a member but can it also do it before the first member?

Barry
  • 286,269
  • 29
  • 621
  • 977
user183833
  • 228
  • 1
  • 8
  • 3
    If the function only accesses the `A` part, then why does it take a `Pair` input rather than an `A` input??? – barak manos Sep 20 '16 at 16:23
  • Actually the example is generic in order to describe my question. I want to know if this is undefined. But let's say that it is a part of a set of functions that implement a set of generic behaviors and must have the same signature. – user183833 Sep 20 '16 at 16:26
  • 1
    Related: http://stackoverflow.com/questions/15994237/how-is-is-standard-layout-useful – Mysticial Sep 20 '16 at 16:37

2 Answers2

4

I think it's defined behavior, assuming Pair is standard-layout. Otherwise, it's undefined behavior.

First, a standard layout class and its first member share an address. The new wording in [basic.compound] (which clarifies earlier rules) reads:

Two objects a and b are pointer-interconvertible if:
* [...]
* one is a standard-layout class object and the other is the first non-static data member of that object, or, [...]
* [...]
If two objects are pointer-interconvertible, then they have the same address, and it is possible to obtain a pointer to one from a pointer to the other via a reinterpret_cast (5.2.10).

Also from [class.mem]:

If a standard-layout class object has any non-static data members, its address is the same as the address of its first non-static data member. Otherwise, its address is the same as the address of its first base class subobject (if any).

So the reinterpret_cast from A to Pair is fine. If then function only ever access the a object, then that access well-defined, as the offset of A is 0, so the behavior is equivalent to having function take an A& directly. Any access to the b would be undefined, obviously.


However, while I believe the code is defined behavior, it's a bad idea. It's defined behavior NOW, but somebody someday might change function to refer to pair.b and then you're in a world of pain. It'd be a lot easier to simply write:

void function(A& a) { ... }
void function(Pair& p) { function(p.a); }

and just call function directly with your a.

Barry
  • 286,269
  • 29
  • 621
  • 977
  • First of all thanks for your answer. Reading about standard layout classes I saw that for an class to have standard layout all the members must have the same access control. And it seems strange to me, what could and would change if Pair had for example a third private member. Why would the compiler change the ordering? – user183833 Sep 20 '16 at 17:10
  • @user183833 POD (the precursor to standard layout) was intended for compatibility with [tag:C]. code that used C++ specific constructs was permitted to mess around with structure layout in any way it chose; it could put private data first, or last, or in the middle. I think it could even put private data on its own separate memory space, but I am not sure. When POD evolved into standard layout, some requirements where removed: every compiler already made POD with a constructor have a standard layout, so they where codifying existing practice in a useful way – Yakk - Adam Nevraumont Sep 20 '16 at 17:33
  • @Barry As for the last thing you say. [Here](http://stackoverflow.com/questions/39601838/implementing-a-hashmap-using-a-hashtable-implementation) is a use case. – user183833 Sep 26 '16 at 09:31
-1

Yes, it's undefined behaviour.

In a struct pair, there can be padding between a and b. An assignment to a member of a struct can modify any padding in the struct. So an assignment to pair.a can modify memory where it thinks there is padding in the struct, where in reality there is just random memory following the memory occupied by your a.

gnasher729
  • 51,477
  • 5
  • 75
  • 98
  • 1
    Thank you for your response. One thing how can an assignment to an object modify bytes outside of it? How and why would it happen? – user183833 Sep 20 '16 at 16:38