空基类是否应该影响派生类的布局? C++标准(引用N3242草案),下面的子对象[对象]:

空基类是否应该影响派生类的布局? C++标准(引用N3242草案),下面的子对象[对象]:,c++,standards,unspecified-behavior,C++,Standards,Unspecified Behavior,除非对象是位字段或零的基类子对象 大小,则该对象的地址是它的第一个字节的地址 占有。两个既不是位字段也不是基的不同对象 零大小的类子对象应具有不同的地址 现在,给出以下代码片段: struct empty { }; struct member: empty { }; struct derived: empty { member m; }; int main(void) { printf("%d", sizeof(derived)); return 0; } 我相信打印出代码<

除非对象是位字段或零的基类子对象 大小,则该对象的地址是它的第一个字节的地址 占有。两个既不是位字段也不是基的不同对象 零大小的类子对象应具有不同的地址

现在,给出以下代码片段:

struct empty { };
struct member: empty { };
struct derived: empty { member m; };

int main(void)
{
    printf("%d", sizeof(derived));
    return 0;
}
我相信打印出代码< 2 >代码> Visual C++ 2010打印出代码> 1 <代码>。我怀疑gcc采用的标准意味着,如果类型表示不同的对象,就不能对其存储进行别名。我打赌MSVC的标准是,如果一个子对象的大小为零,你可以做任何你想做的事情


这是未指定的行为吗?

这取决于实现


该标准明确允许空基优化,但不要求空基优化。事实上,该标准对内存中类的布局没有太多要求,只要求某些类的布局相互兼容(而不是通用布局)。还指定了成员的顺序(当没有插入可访问性说明符时),但允许填充、页眉、页脚和各种奇怪的内容。

在C++11标准的最终版本中,该段修改为:

除非对象是位字段或零的基类子对象 大小,则该对象的地址是它的第一个字节的地址 占有。两个不是位字段的对象可能具有相同的属性 如果一个是另一个的子对象或至少一个是 大小为零且类型不同的基类子对象; 否则,它们应具有不同的地址


虽然我不确定我是否理解这与对象的大小有什么关系。

展开我之前的评论:

对象由其地址标识。如果比较同一类型的两个对象的地址(如指针),并且它们比较相等,则认为指针指向同一对象

不同类型的对象不能通过这种方式直接进行比较,因此允许它们具有相同的地址。一个例子是结构及其第一个成员。它们不能属于同一类型。基类和派生类都不能,因此如果基类为空,它们可能具有相同的地址

但是,基类和派生类的第一个成员可以是同一类型。这不是问题,除非基类也是空的,并且编译器尝试空基类优化。在这种情况下,我们可以让指向相同类型的两个不同对象的指针比较相等,因此认为它们是同一个对象

因此,如果成员具有不同的类型(empty和char),那么它们可以具有相同的地址。如果它们属于同一类型,则不能,因为这将破坏对象标识的测试,例如
If(this!=&that)
,有时用于测试诸如自分配之类的内容


顺便说一句,微软同意这是他们的编译器中的一个bug,但还有其他更紧迫的问题需要首先解决。

在这个线程中有很好的解释。我只是想补充一点,为了解决这个结构膨胀的问题,您可以简单地将
设为空
类a模板,以便使用不同的模板参数实例化它,使其成为不同的类:

template<class T>
struct empty { };
struct member: empty<member> { };
struct derived: empty<derived> { member m; };

int main(void)
{
    printf("%d\n", sizeof(derived));
    return 0;
}
模板
结构空{};
结构成员:空{};
派生结构:空{member m;};
内部主(空)
{
printf(“%d\n”,sizeof(派生));
返回0;
}
输出
1


这就是避免在大型项目中使用
boost::noncopyable
的原因。

哪个版本的gcc?当
member
设置为
char
@envu时,gcc 4.7在此输出1,该版本由另一个SDK指定。如果成员具有不同的类型(空和字符),则它们可以具有相同的地址。如果它们属于同一类型,则不能,因为这将破坏对象标识的测试,例如
If(this!=&that)
。我认为Bo Persson是正确的。据我所见,VC的行为不符合要求。N3290 10/8和C++03 10/7说:
具有相同类类型且属于同一最派生对象的两个子对象不能分配到同一地址
@BoPersson,你能回答这个问题吗?考虑到10/8的措辞,我认为这是最恰当的解释;printf(“%d”,static_cast(&d)=static_cast(&d.m));打印1还是打印0?这决定了大小是1还是>1。顺便说一下,标准禁止标准布局类具有与第一个成员相同类型的基类,可能正是出于这个原因。