假设我们在成员函数中有以下两个不等式
this <= (void *) &this->data_member
和
&this->data_member < (void *) (this+1)
他们保证是真的吗? (在我检查过的几个案例中,它们似乎都是真的 . )
编辑:我错过了&符号,现在这是不正当的正确形式 .
从CPP标准草案4713:
6.6.2对象模型[intro.object] / 7一个简单可复制或标准布局类型的对象(6.7)应占用连续的存储字节 . 12.2类成员[class.mem] / 18分配具有相同访问控制(第14章)的(非联合)类的非静态数据成员,以便后面的成员在类对象中具有更高的地址 . 12.2类成员[class.mem] / 25如果标准布局类对象具有任何非静态数据成员,则其地址与其第一个非静态数据成员的地址相同 . 否则,其地址与其第一个基类子对象(如果有)的地址相同 .
综合以上所有内容,我们可以说第一个等式至少适用于可复制的对象 .
也来自在线cpp reference:
比较两个指向对象的指针(转换后)的结果定义如下:1)如果两个指针指向同一个数组的不同元素,或指向同一个数组的不同元素内的子对象,则指向该元素的指针较高的下标比较大 . 换句话说,它们比较指针的结果与它们指向的元素的索引的比较结果相同 . 2)如果一个指针指向数组的元素,或指向数组元素的子对象,而另一个指针指向一个超过数组的最后一个元素的指针,则后一指针将指向更大的指针 . 指向单个对象的指针被视为指向一个数组的指针:&obj 1比较大于&obj(因为C 17)
因此,如果您的 data_member 是 not 指针并且没有单独分配内存,那么您发布的方程式至少可以保留至少可复制的对象 .
data_member
不,这是一个反例
#include <iostream> struct A { int a_member[10]; }; struct B : public virtual A { int b_member[10]; void print_b() { std::cout << static_cast<void*>(this) << " " << static_cast<void*>(std::addressof(this->a_member)) << " " << static_cast<void*>(this + 1) << std::endl; } }; struct C : public virtual A { int c_member[10]; void print_c() { std::cout << static_cast<void*>(this) << " " << static_cast<void*>(std::addressof(this->a_member)) << " " << static_cast<void*>(this + 1) << std::endl; } }; struct D : public B, public C { void print_d() { print_b(); print_c(); } }; int main() { D d; d.print_d(); }
使用可能的输出(作为seen here)
0x7fffc6bf9fb0 0x7fffc6bfa010 0x7fffc6bfa008 0x7fffc6bf9fe0 0x7fffc6bfa010 0x7fffc6bfa038
请注意 a_member 位于 this 指向的 B 之外 print_b
a_member
this
B
print_b
对象的值在其表示内,并且此表示是一个unsigned char序列:[basic.types]/4
类型T的对象的对象表示是由类型T的对象占据的N个无符号字符对象的序列,其中N等于sizeof(T) . 类型T的对象的值表示是参与表示类型T的值的位集 . [...]
因此,对于形式主义原教旨主义者来说,确实没有定义 Value ,但这一术语出现在访问的定义中:[defns.access]:
读取或修改对象的值
那么完整对象的值的子对象部分的值是什么?我想这是标准的意图 .
如果将对象指针转换为 unsigned char* ,则比较应为true . (这是一种常见的做法,属于规格不足core issue #1701)
unsigned char*
完整standard text相当于:
[expr.rel] - 4:比较不等指针到对象82的结果是根据与以下规则一致的部分顺序定义的:
我们在这里处理的是部分订单,而不是总订单 . 这确实意味着 a < b 和 b < c 意味着 a < c ,但其他并不多 .
a < b
b < c
a < c
(注82)为了这个目的,非数组对象被认为是单元素数组的元素,具有“指向元素一的结尾指针”的直观含义/行为 .
(4.1)如果两个指针指向同一个数组的不同元素或其子对象,则指向具有较高下标的元素的指针需要比较更大 .
指向不同成员的指针不是指向同一数组的元素(子对象)的指针 . 此规则不适用 .
(4.2)如果两个指针指向同一对象的不同非静态数据成员,或者指向这些成员的子对象,则递归地指向稍后声明的成员的指针需要比较更大,前提是两个成员具有相同的访问控制([class.access]),两个成员都不是零大小的子对象,并且它们的类不是联合 .
此规则仅将指针与同一对象的数据成员相关联,而不是指向不同对象的数据成员 .
(4.3)否则,两个指针都不需要比另一个更大 .
因此,您没有得到标准的任何保证 . 你是否能找到一个真实世界的系统,你得到的结果与你预期的不同是另一个问题 .
4 回答
从CPP标准草案4713:
综合以上所有内容,我们可以说第一个等式至少适用于可复制的对象 .
也来自在线cpp reference:
因此,如果您的
data_member
是 not 指针并且没有单独分配内存,那么您发布的方程式至少可以保留至少可复制的对象 .不,这是一个反例
使用可能的输出(作为seen here)
请注意
a_member
位于this
指向的B
之外print_b
对象的值在其表示内,并且此表示是一个unsigned char序列:[basic.types]/4
因此,对于形式主义原教旨主义者来说,确实没有定义 Value ,但这一术语出现在访问的定义中:[defns.access]:
那么完整对象的值的子对象部分的值是什么?我想这是标准的意图 .
如果将对象指针转换为
unsigned char*
,则比较应为true . (这是一种常见的做法,属于规格不足core issue #1701)完整standard text相当于:
我们在这里处理的是部分订单,而不是总订单 . 这确实意味着
a < b
和b < c
意味着a < c
,但其他并不多 .(注82)为了这个目的,非数组对象被认为是单元素数组的元素,具有“指向元素一的结尾指针”的直观含义/行为 .
指向不同成员的指针不是指向同一数组的元素(子对象)的指针 . 此规则不适用 .
此规则仅将指针与同一对象的数据成员相关联,而不是指向不同对象的数据成员 .
因此,您没有得到标准的任何保证 . 你是否能找到一个真实世界的系统,你得到的结果与你预期的不同是另一个问题 .