数据成员地址是否位于(this)和(this + 1)之间?

时间:2018-12-10 11:26:59

标签: c++ language-lawyer

假设成员函数中存在以下两个不等式

this <=  (void *) &this->data_member

&this->data_member < (void *) (this+1) 

它们是否保证是真的? (在我检查过的某些情况下,它们似乎是正确的。)

编辑:我错过了&符,现在它是不等式的正确形式。

4 个答案:

答案 0 :(得分:5)

根据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不是不是指针,并且没有单独分配内存,那么您发布的方程式将很有效 至少可以复制的对象。

答案 1 :(得分:4)

完整的standard text等于:

  

[expr.rel]-4:比较对象的不相等指针 82 的结果是根据偏序定义的遵循以下规则:

我们正在处理部分订单,而不是全部订单。这确实意味着a < bb < c暗示着a < c,但没有太多其他意义。

(注释82指出,为此目的,非数组对象被视为单元素数组的元素,其直观含义/行为是“指向元素末尾的指针”。)

  

(4.1)       如果两个指针指向同一数组的不同元素或其子对象,则需要使用具有较高下标的元素的指针进行比较。

指向不同成员的指针不是指向同一数组的元素(的子对象)的指针。此规则不适用。

  

(4.2)       如果两个指针递归地指向同一对象的不同非静态数据成员或此类成员的子对象,则要求后面声明的成员的指针比较大,前提是两个成员具有相同的访问控制([class.access]),两个成员都不是零大小的子对象,并且它们的类也不是联合。

此规则仅将指针关联到同一对象的数据成员,而不是不同对象的数据成员。

  

(4.3)       否则,两个指针都不要求比另一个更大。

因此,您没有从标准中获得任何保证。您是否能找到一个现实世界中获得的结果与预期不同的系统是另一个问题。

答案 2 :(得分:0)

对象的值在其表示形式之内,并且该表示形式是无符号字符序列:[basic.types]/4

  

类型T的对象的对象表示形式是类型T的对象占用的N个无符号字符对象的序列,其中N等于sizeof(T)。   类型T的对象的值表示形式是一组位,它们表示类型T的值。[...]

因此对于形式主义原教旨主义者而言,确实没有定义 value ,但该术语出现在 access [defns.access]

的定义中
  

读取或修改对象的值

那么子对象的值是完整对象值的一部分吗?我想这就是标准的目的。

如果将对象指针转换为unsigned char*,则比较应该为true。 (这是一种常见的做法,属于规格不足的core issue #1701

答案 3 :(得分:0)

不,这是一个反例

#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_memberBthis指向的print_b之外