Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
313 views
in Technique[技术] by (71.8m points)

c++ - What happened to the "aggregate or union type that includes one of the aforementioned types" strict aliasing rule?

Previously, in basic.lval, there was this bullet point:

an aggregate or union type that includes one of the aforementioned types among its elements or non-static data members (including, recursively, an element or non-static data member of a subaggregate or contained union),

In the current draft, it is gone.

There is some background information at WG21's site: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1359r0.html#2051:

The aliasing rules of 7.2.1 [basic.lval] paragraph 10 were adapted from C with additions for C++. However, a number of the points either do not apply or are subsumed by other points. For example, the provision for aggregate and union types is needed in C for struct assignment, which in C++ is done via constructors and assignment operators in C++, not by accessing the complete object.

Can anyone explain to me, what this means? What has this strict aliasing rule to do with struct assignment in C?

cppreference says about this rule:

These bullets describe situations that cannot arise in C++

I don't understand, why it is true. For example,

struct Foo {
    float x;
};

float y;
float z = reinterpret_cast<Foo*>(&y)->x;

The last line seems to do what the bullet point describes. It accesses y (a float) through an aggregate, which includes a float (member x).

Can anyone shed some light on this?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

The lvalue you use to access the stored value of y is not *reinterpret_cast<Foo*>(&y), of type Foo, but it is reinterpret_cast<Foo*>(&y)->x, which has the type float. Accessing a float using an lvalue of type float is fine. In C++, you can not "access the value of a union or struct" (as whole), you can only access individual members. The rationale you quoted points to a difference between C and C++:

  struct X { int a, b; };
  struct X v1 = {1, 2}, v2;
  v2 = v1;

In C, the standard says that the assignment loads the value of v1 (as whole) to assign it to v2. Here the values of the objects v1.a and v2.b (both have types int) are accessed using an lvalue of type struct X (which is not int).

In C++, the standard says that the assignment calls the compiler generated assignment operator which is equivalent to

struct X {
   ...
   struct X& operator=(const struct X&other)
   {
       a = other.a;
       b = other.b;
   }
};

In this case, calling the assignment operator does not access any value, because the RHS is passed by reference. And executing the assignment operator accesses the two int fields separately (which is fine, even without the aggregate rule), so this is again not accessing a value through an lvalue of type struct X.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...