关于 sizeof winrt Demo 对象

about the sizeof winrt Demo object

我很好奇一个非常简单的 Demo 对象的大小,所以,我正在编写以下代码

</p>

#include <windows.h>
#include "winrt/base.h"
#include <iostream>
#pragma comment(lib, "windowsapp")
/*
cl /nologo /await /std:c++latest /wd4002 /EHsc base_so.cpp
*/
using namespace std;
using namespace winrt;
using namespace winrt::impl;

struct IDemo;

template <typename D>
struct consume_IDemo
{
  void hello();
};

template <> struct consume<IDemo> { template <typename D> using type = consume_IDemo<D>; };

template <typename D> void consume_IDemo<D>::hello()
{
  WINRT_SHIM(D)->hello();
}

struct WINRT_EBO __declspec(uuid("3A44B7CC-9CB6-4512-8CAD-6400E662D865")) 
IDemo : Windows::Foundation::IInspectable, consume_t<IDemo>
{  
  IDemo(std::nullptr_t = nullptr) noexcept {};
};

template <> struct abi<IDemo>
{
  struct type : IInspectable
  {
    virtual HRESULT hello() = 0;
  };  
};

template <typename D>
struct produce<D,IDemo> : produce_base<D,IDemo>
{
  HRESULT hello() override
  {
    shim().hello();
    return S_OK;
  }
};

struct Demo : implements<Demo,IDemo>
{ 
  Demo()
  {
    cout << "sizeof Demo 0x" << hex << sizeof(*this) << dec << endl;
    cout << "sizeof m_references 0x" << hex << sizeof(std::atomic<std::conditional_t<1, uintptr_t, uint32_t>>) << dec << endl;
    cout << "is_composing " << is_composing << endl;
    cout << "outer " << outer() << endl;    
  }

  HRESULT hello()
  {
    cout << __FUNCTION__ << endl;
    return S_OK;
  }
};

int main()
{
  Demo d;
}

输出为

sizeof 演示 0x18
sizeof m_references 0x8
is_composing 0
外部 0000000000000000

我认为 Demo 的 sizeof 应该是 0x10 (64 机器) : sizeof(m_references)+sizeof(produce) 那么,额外的 8 个字节是多少?非常感谢!

要么是padding,要么是v-tables。也许两者都...

编译器可能会为每个至少声明了一个虚方法的基 class 插入一个 v-table 指针。 (顺便说一句,当你从具体的 class 到非第一个基础 class 进行 C 转换时,static_cast 或 dynamic_cast,编译器将改变指向 base-class 或其 v-table 的指针值。)

让我们分解一下。

Demo 继承自 implements<Demo,IDemo>

implements定义如下:

struct implements : impl::producers<D, I...>, impl::base_implements<D, I...>::type
{

现在我们进入 WinRT 噪音。但它似乎确实暗示了多重继承。但是用调试器来解决这个问题更容易……你去吧。第一个 vtable 用于 IUnknown。另一个是IInspectable.

相关的东西

所以这是有道理的。每个 v-table 都是一个 8 字节的指针。而 m_references 也是 8 个字节。 8+8+8 = 24 = 0x18