如何通过聚合访问对象的存储 [英] How to access an object's storage through an aggregate

查看:109
本文介绍了如何通过聚合访问对象的存储的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在Lvalues and Rvalues中,[basic.lval](3.10)中,C ++标准包含一个类型列表,以便通过这种类型的glvalue访问对象的存储值是有效的第10段)。具体来说,它说:

In "Lvalues and rvalues", [basic.lval] (3.10), the C++ standard contains a list of types such that it is valid to "access the stored value of an object" through a glvalue of such a type (paragraph 10). Specifically, it says:


如果程序试图通过除以下类型之一的glvalue访问对象的存储值行为未定义:

If a program attempts to access the stored value of an object through a glvalue of other than one of the following types the behavior is undefined:


  • 对象的动态类型

  • the dynamic type of the object,

[关于CV和签名/未签名的一些不重要的详细信息]

[some unimportant details about CV and signed/unsigned]

包含上述类型之一的聚合或联合类型其元素或非静态数据成员(包括递归地包含子聚合或包含的union的元素或非静态数据成员)

一些更多的东西]

聚合规则是什么意思?如何通过一些一般聚合类型的glvalue来访问对象的存储值?!

What exactly does the "aggregate" rule mean? How do I access an object's stored value through a glvalue of some general aggregate type?!

我画的像这样:

int a = 10;                                      // my "stored value"

struct Foo { char x; float y; int z; bool w; };  // an aggregate

reinterpret_cast<Foo&>(a).y = 0;                 // ???

最终转换不会生成一个glvalue的包含动态类型 a

Doesn't the final cast produce a glvalue of "an aggregate type that includes the dynamic type of a", and thus make this valid?

推荐答案

列表不是为您提供替代方法来访问对象,而是作为列表的脚注指示,列出对象可能有别名的所有方式。考虑下面的例子:

The intent of that list is not to provide you alternate methods to access an object, but rather as the footnote to the list indicates, to list all the ways an object might be aliased. Consider the following example:

struct foo
{
    char x; 
    float y; 
    int z; 
    bool w;
};

void func( foo &F, int &I, double &D )
{
    //...
}

这个列表说的是访问 F 与访问 I 相同的底层对象。如果您为 I 传递对 Fz 的引用,可能会发生这种情况,如下所示:

What that list is saying is that accesses to F may also access the same underlying object as accesses to I. This could happen if you passed a reference to F.z in for I, like this:

func(F, F.z, D); 

另一方面,您可以安全地假设不能访问 F 访问与 D 相同的底层对象,因为 struct foo 不包含任何类型的成员 double

On the other hand, you can safely assume no access to F accesses the same underlying object as D, because struct foo does not contain any members of type double.

这是真的,即使有些joker这样做:

That's true even if some joker does this:

union onion
{
    struct foo F;
    double D;
};

onion o; 
int i;

func( o.F, i, o.D );  // [class.union] (9.5) wants a word with you.  UB.

我不确定 union 是你的问题的核心。但是 union 示例之前的部分突出显示了为什么存在聚合规则。

I'm not sure that the union was central to your question. But the part before the union example highlights why the aggregate rule exists.

现在让我们考虑你的例子: reinterpret_cast< Foo&>(a).y = 0; [expr.reinterpret.cast](5.2.10),第11段有这样说:

Now let's consider your example: reinterpret_cast<Foo&>(a).y = 0; [expr.reinterpret.cast] (5.2.10), paragraph 11 has this to say:


类型 T1 的左值表达式可以转换为类型对
的引用 T2 如果指向 T1 的类型的表达式可以显式
转换为类型指针 reinterpret_cast 使用 T2
是一个引用 reinterpret_cast< T&>(x)具有与
相同的效果转换 *使用内置的& * 重新创建reinterpret_cast< T *>(& x)
运算符(对于 reinterpret_cast< T&&>(x))。结果
引用与源lvalue相同的对象,但使用不同的
类型。结果是对于左值引用类型的左值,或对函数类型的
右值引用和对对象类型的右值
引用的x值。没有临时是
创建,没有复制,并且不调用构造函数
(12.1)或转换函数(12.3)。 71

An lvalue expression of type T1 can be cast to the type "reference to T2" if an expression of type "pointer to T1" can be explicitly converted to the type "pointer to T2" using a reinterpret_cast. That is, a reference cast reinterpret_cast<T&>(x) has the same effect as the conversion *reinterpret_cast<T*>(&x) with the built-in & and * operators (and similarly for reinterpret_cast<T&&>(x)). The result refers to the same object as the source lvalue, but with a different type. The result is an lvalue for an lvalue reference type or an rvalue reference to function type and an xvalue for an rvalue reference to object type. No temporary is created, no copy is made, and constructors (12.1) or conversion functions (12.3) are not called.71

71 这有时被称为类型双关语。 / p>

71 This is sometimes referred to as a type pun.

在你的例子的上下文中,它说如果转换一个指针是合法的 - int 指向< - Foo 的指针,然后您的 reinterpret_cast< Foo&是合法的,并产生一个左值。 (第1段告诉我们它将是一个左值。)而且,正如我读的,根据第7段,指针转换本身是OK:

In the context of your example, it's saying that if it's legal to convert a pointer-to-int to a pointer-to-Foo, then your reinterpret_cast<Foo&)(a) is legal and produces an lvalue. (Paragraph 1 tells us it will be an lvalue.) And, as I read it, that pointer conversion is itself OK, according to paragraph 7:


指向一个对象的指针可以被显式转换为一个指向
不同对象类型的指针。当类型指向 T1 的prvalue v
时,转换为类型指向 cv T2 ,结果是 static_cast< cv
T2 *>(static_cast< cv void * ;如果 T1 T2 都是标准布局类型)和 T2 的对齐
要求不比 T1 的要求更严格。将指向 T1 类型的prvalue转换为指向 T2
类型指针 T1 T2 是对象类型,其中 T2 没有比$ T1 更严格的
),并返回到其原始类型,产生原始指针值。任何
其他此类指针转换的结果未指定。

A pointer to an object can be explicitly converted to a pointer to a different object type. When a prvalue v of type "pointer to T1" is converted to the type "pointer to cv T2", the result is static_cast<cv T2*>(static_cast<cv void*>(v)) if both T1 and T2 are standard-layout types (3.9) and the alignment requirements of T2 are no stricter than those of T1. Converting a prvalue of type "pointer to T1" to the type "pointer to T2" (where T1 and T2 are object types and where the alignment requirements of T2 are no stricter than those of T1) and back to its original type yields the original pointer value. The result of any other such pointer conversion is unspecified.

您具有兼容对齐约束的标准布局类型。所以,你有一个类型双关,产生一个左值。您列出的规则不会自己使其未定义。

You have standard-layout types with compatible alignment constraints. So, what you have there is a type pun that yields an lvalue. The rule you listed does not on its own make it undefined.

那么什么可能会使它未定义?好吧,一个,[class.mem](9.2)第21段提醒我们,指向一个标准布局struct对象的指针指向它的初始成员,反之亦然。所以,在你的类型双关语之后,你留下一个引用 Foo ,使 Foo x 位于与 a 相同的位置。

So what might make it undefined? Well, for one, [class.mem] (9.2) paragraph 21 reminds us that a pointer to a standard layout struct object points to its initial member, and vice versa. And so, after your type pun, you're left with a reference to Foo, such that Foo's x is at the same location as a.

并且这是我的语言律师。我知道在我的直觉,访问 Foo 通过该franken参考是在最好实施定义或未指定。我不能找到它明确放逐到 undefined 行为的地方。

And... this is where my language lawyering peters out. I know in my gut that accessing Foo through that franken-reference is at best implementation defined or unspecified. I can't find where it's explicitly banished to the realm of undefined behavior.

但是,我想我回答了你原来的问题:为什么总规则有哪些?它给你一个非常基本的方法来处理潜在的别名,而无需进一步的指针分析。

But, I think I answered your original question: Why is the aggregate rule there? It gives you a very basic way to rule on potential aliases without further pointer analysis.

这篇关于如何通过聚合访问对象的存储的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆