C++类内的成员是否保证是连续的?

3

C++中的类成员是否保证是连续的?

我尝试在几乎所有流行的C++编译器上运行以下代码,并且它们全部都产生了相对地址为4的结果,这是变量y的地址。 这是巧合吗,还是语言规范保证了这种方式?编译器不可能使成员x和y与类的基本地址/彼此不连续吗?

请注意,此线程不能回答这个问题。

#include <iostream>

using namespace std;

class A {
public:

    void f(){
        cout << &(this->y) << endl;
    }

    int x, y;
};


int main(int argc, const char* argv[])
{
    A *a = 0;
    a->f();

    return 0;
}

1
这很复杂,标准提出了一些要求,但也允许很大的自由度。从这里开始(兔子洞很深):http://en.cppreference.com/w/cpp/language/object 和这里:http://en.cppreference.com/w/cpp/language/memory_model - Richard Critten
2
@RichardCritten:比起一个洞,更像是一个兔子的迷宫,甚至是整个兔子生态系统。 - Bathsheba
1
@Bathsheba 你觉得怎么样:“你身处于迷宫中,到处都是相似的曲折小通道”? - Richard Critten
@RichardCritten:或者这个地方;书籍是可选的:https://en.wikipedia.org/wiki/The_Library_of_Babel - Bathsheba
1
解除引用空指针是未定义行为。不要在xy之间的间隙上纠结,即使A没有数据成员,即使A::f为空,这仍然是未定义行为。你不能断言“所有编译器都返回4,即y的偏移量”。 - MSalters
显示剩余6条评论
1个回答

6
因为您的类不是多态类型,没有基类,并且所有成员都是公共的,所以保证了x的地址就是类的地址。此外,y的地址保证在x的地址之后,尽管它们之间可能有任意数量的填充。所以,是的,您的结果是巧合。如果您的类是多态的,即在它或基类中有一个虚函数,或成员是受保护的或私有的,则所有赌注都无效。因此,在您的情况下,(void*)&(this->x)是(void*)this,而this->y的地址必须高于this->x的地址。最后,如果您需要类成员是连续的,并且可以通过指针算术相互访问,请使用
int x[2];

作为会员而不是。


2
@Oliv:“可能引起”的关键在于:由于这个原因,你需要假设它会发生,否则你就不能编写可移植的C++代码。 - Bathsheba
@Oliv:我认为标准并不保证标准布局结构体中成员之间的填充,只保证开头没有填充。 - AndyG
@AndyG 这真的很奇怪,为什么称它们为标准布局,如果标准没有定义它们的布局。我认为标准布局结构存在的目的是为了允许不同可执行文件之间进行通信。然而,如果它们的布局没有标准化,那么它们的布局将由每个编译器唯一指定,这就是非标准布局结构的情况,这使得这个概念绝对毫无意义! - Oliv
@Bathsheba 标准布局结构有什么充分的规范目的?我实际上从未发现过这个标准概念的任何应用。 - Oliv
2
@Bathsheba 我认为标准布局结构的规范对于与C语言的兼容性是必要的,但这并不足够。例如,编译器在C++中可能会比在C中添加更多的填充。 - Oliv
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接