贴片新品如何知道要创建哪种布局?

时间:2016-10-09 18:01:29

标签: c++ c++14 language-lawyer placement-new

#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的例子。但是,该示例可能仅仅因为其中的类是标准布局而起作用。

4 个答案:

答案 0 :(得分:2)

  

保证由new创建的布局适合大小为(B)且偏移为零的缓冲区

new中命名的类型作为其参数B。正在制作B,而不是D。类型B&#34;什么都不知道&#34;关于DD的声明对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)

新表达式中发生了两件事:

  1. 通过调用operator new来分配类型的内存(没有 新表达)

  2. 构建所需类型。

  3. 通常,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的布局相同 - 第二个布局。