#include <iostream>
#include <typeinfo>
struct A { int a; };
struct B : virtual A { int b; };
struct C : virtual A { int c; };
struct D : B,C { int d; };
int main()
{
D complete;
B contiguous;
B & separate = complete;
B * p[2] = {&separate, &contiguous};
// two possible layouts for B:
std::cout<< (int)((char*)(void*) &p[0]->a -(char*)(void*)&p[0]->b)<<" "<< sizeof(*p[0])<< "\n";
std::cout<< (int)((char*)(void*) &p[1]->a -(char*)(void*)&p[1]->b)<<" "<< sizeof(*p[1])<< "\n";
alignas(B) char buff[sizeof(B)];
void * storage = static_cast<void*>(buff);
// new expression skips allocation function:
auto pointer= new (storage) B; // Which layout to create?
std::cout << typeid(pointer).name()<<"\n";
pointer->~B(); // Destructor knows layout through typed pointer.
}
// sample output (Debian 8, amd64):
// 24 16
// 4 16
// P1B
C ++ 14标准中是否有一节需要'new'来创建特定的布局?有保证吗? 由new创建的布局适合大小为(B)且偏移为零的缓冲区?
编辑:您能否使用grep友好的术语或提供参考?我在问题中添加了对标准的引用。
考虑上面的示例输出:24号告诉你什么?缓冲区的大小是多少?
标准中可能有一条声明,即派生出来的对象始终是对象表示的简单连续副本, 但我还没找到这个。
我们对new的了解是它应该与完整的对象类型一起使用。 [expr.new]
在[class.dtor]§12.4(14)中有一个带有placement选项的new-expression的例子。但是,该示例可能仅仅因为其中的类是标准布局而起作用。
答案 0 :(得分:2)
保证由new创建的布局适合大小为(B)且偏移为零的缓冲区
从new
中命名的类型作为其参数B
。正在制作B
,而不是D
。类型B
&#34;什么都不知道&#34;关于D
。 D
的声明对B
没有影响; B
声明可以放入D
未出现的翻译单元中,但程序中的所有地方都会就B
的大小达成一致,并且是布局,无论如何是否D
在这些地方也是已知的。
T
类型的C ++对象的大小为sizeof T
。这意味着它适合sizeof T
个字节;它的表示不需要(sizeof T) + k
字节,k > 0
。
答案 1 :(得分:1)
没有选项来创建你称之为&#34;单独的&#34;布局,除了创建派生类型,并从中捕获|
。
&#34; B
的布局作为其派生类的一部分&#34;与&#34; B
&#34;的布局不同。展示位置B
和常规new
使用基于类型本身的布局,是默认的独立布局。
保证新设置的布局适合大小为
new
的缓冲区?
sizeof(B)
返回sizeof(B)
本身的大小,而不是B
- 作为其他类的一部分。这就是存储独立B
所需的所有空间,无论您为其分配内存的方式如何。
答案 2 :(得分:0)
新表达式中发生了两件事:
通过调用operator new来分配类型的内存(没有 新表达)
构建所需类型。
通常,new new可以使用大小,这是由新表达式中的编译器传递的。有一个新的位置(提供存储),程序员负责提供足够大的存储空间来保存所需的类型。
无论如何:不要混合分配和对象构造。这是两个截然不同的任务。
答案 3 :(得分:0)
只是一种精度:实现虚拟继承的一种方法是在所有自己的成员字段声明之后,在类的末尾推送(所有)虚拟基类。这应该是D类和B类的组织。
class D:
-----
pvmt for B, D (include shift to find A)
int b;
-----
pvmt for C (include shift to find A)
int c;
-----
int a;
-----
class B:
-----
pvmt for B (include shift to find A)
int b;
-----
int a;
-----
class C:
-----
pvmt for C (include shift to find A)
int c;
-----
int a;
-----
选择new
的布局不是void* rawObject= new (storage) B;
;事实上,您创建了一个具体的B对象。因此布局与contiguous
的布局相同 - 第二个布局。