Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/139.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
&引用;没有与第一个非静态数据成员类型相同的基类; 我在C.P.ST.C++上没有得到答复。_C++_Struct_C++11 - Fatal编程技术网

&引用;没有与第一个非静态数据成员类型相同的基类; 我在C.P.ST.C++上没有得到答复。

&引用;没有与第一个非静态数据成员类型相同的基类; 我在C.P.ST.C++上没有得到答复。,c++,struct,c++11,C++,Struct,C++11,我只是想引用一下我的帖子,稍作修改 标准布局类9/6的最后一个要求是必要的还是有用的 提供脚注说明: 这样可以确保两个子对象 具有相同的类类型,并且 属于同一个最派生的对象 不在同一地址分配 (5.10) 单独来看,脚注是不正确的。两个带有 公共基类可以同时生成基类的两个实例 同一地址 struct A {}; struct B : A {}; struct C : A {}; struct D : B, C {}; D d; static_cast<A*>(static_cas

我只是想引用一下我的帖子,稍作修改


标准布局类9/6的最后一个要求是必要的还是有用的

提供脚注说明:

这样可以确保两个子对象 具有相同的类类型,并且 属于同一个最派生的对象 不在同一地址分配 (5.10)

单独来看,脚注是不正确的。两个带有 公共基类可以同时生成基类的两个实例 同一地址

struct A {};
struct B : A {};
struct C : A {};
struct D : B, C {};

D d;
static_cast<A*>(static_cast<B*>(&d))
   == static_cast<A*>(static_cast<C*>(&d)); // allowed per 1.8/5
struct A{};
结构B:A{};
结构C:A{};
结构D:B,C{};
D;
静态浇铸
这表明多重继承可能会带来麻烦和需要
不允许在标准布局类中使用,以确保:;
然而,这最终是允许的,鉴于此,要求
没有道理


参考1.8/5-6:

5除非是位字段(9.6),否则 大多数派生对象应具有 非零尺寸,且应占据一个或多个 更多字节的存储空间。基类 子对象的大小可能为零。一 可复制的或不可复制的对象 应采用标准布局类型(3.9) 占用连续的存储字节

6除非对象是位字段或 大小为零的基类子对象 那个对象的地址就是地址 它占用的第一个字节的。两个 两者都不是的不同对象 位字段或基类子对象 零尺寸应具有明显的 地址

(脚注)根据“仿佛”规则,允许实现在同一机器地址存储两个对象,或者如果程序无法观察到差异,则完全不存储对象

补充说明: 10.1/8在5.10中提到了相同的神秘内容,但它也只是一个信息注释

[注:…基类子对象的大小可以为零(第9条);但是,不得在同一地址(5.10)分配具有相同类类型且属于同一最派生对象的两个子对象。-结束注]

GCC似乎保证为相同类型的空基子对象提供唯一的地址。这似乎足以保证给定类型的对象由地址唯一标识。这将超出C++对象模型(1.8)的保证。当然这是一个好主意,但标准似乎并不要求这样做。同样,平台ABI可以将这种保证扩展到第一个成员别名为空基的类。该语言规定了ABI的最低要求;一个ABI可以添加一个语言特性,其他ABI也可以这样做,标准追赶的过程很容易出错

我的问题是给定的需求是否在标准的上下文中完成了任何事情,而不是它是否与其他ABI保证一起对用户有用。有证据表明,这样一个独特的地址保证是有意的,而且只是偶然遗漏,这也会使要求更有意义


总结一下答案(或者我的结论):

该要求在理论上并不能保证任何东西,因为它可以确保给定类型的所有对象都有不同的地址。当空基类子对象的地址与另一个对象(另一个基类或成员)冲突时,编译器可以简单地在结构中为其指定任意位置。由于标准布局规则仅描述数据成员的位置(可能是继承的),因此空基的位置仍然未指定,并且可能在类似的标准布局类之间不兼容。(据我所知,非空基地的位置尚未确定,因此不清楚在这种情况下“第一成员”是什么意思,但在任何情况下都必须保持一致。)

实际上,该需求允许实现继续使用现有的ABI,只要它们包括空的基类优化。当违反要求时,现有编译器可能会禁用EBO,以避免基地址与第一个成员的地址重合。如果标准没有以这种方式限制程序,库和程序将不得不用更新的C++0x编译器重新编译…这不值得

具有公共基类的两个空基类必须在同一地址生成基类的两个实例

struct A {};
struct B : A {};
struct C : A {};
struct D : B, C {};

D d;
static_cast<A*>(static_cast<B*>(&d))
   == static_cast<A*>(static_cast<C*>(&d)); // allowed per 1.8/5
我不这么认为。事实上,快速检查我的g++副本表明我有两个不同的a对象地址。也就是说,你上面的代码不是真的

事实上,按照类的编写方式,我们必须有两个A对象。如果两个对象共享同一地址,则它们在任何意义上都不是两个不同的对象。所以,要求对象的实例存在不同的地址

假设A的定义如下:

class A
{
   static std::set<A*> instances;
   A() { instances.insert(this); }
   ~A() { instances.remove(this); }
}
A类
{
静态std::设置实例;
A(){instances.insert(this);}
~A(){instances.remove(this);}
}

如果允许A的两个副本共享一个地址,则此代码将无法正常工作。我相信,正是在这种情况下,我们才决定对A的不同副本使用不同的addresess。当然,正是这种情况的复杂性使我避免了多重继承。

如果你将等式表达式放在
assert()
中,你会发现它失败了。A子对象位于不同的位置。这是正确的行为,无需指定
virtual

struct B : virtual A {};
struct C : virtual A {};
使用
virtual
,根据第二条规则,D已经不是标准布局类。这就是C++ 98、03和'0x.

中的情况。 编辑以反映评论:

再次编辑:没关系,这还不够

标准布局类定义的要点是指定可以与其他语言一起使用的内容。让我们用C作为例子
struct X{
  B base;
  B b;
  int i;
};
struct X{
  B b;
  int i;
};
#include <assert.h>
#include <iostream>

struct E {};
struct D: E { E x ; };

int main()
{
   D d;
   std::cerr << "&d: " << (void*)(&d) << "\n";
   std::cerr << "&d.x: " << (void*)(&(d.x)) << "\n";
   std::cerr << "(E*)&d: " << (void*)(E*)(&d) << "\n";
   assert(reinterpret_cast<E *>(&d) == &d.x); //standard-layout requirement
}
&d: 0x7fffc76c9420 &d.x: 0x7fffc76c9421 (E*)&d: 0x7fffc76c9420 testLayout: testLayout.cpp:19: int main(): Assertion `reinterpret_cast(&d) == &d.x' failed. Aborted