【问题标题】:Overhead for "rich type" struct in C++C++ 中“丰富类型”结构的开销
【发布时间】:2013-03-19 08:18:48
【问题描述】:

我想在编译时跟踪一些当前采用相同类型参数的函数的本质上的“类型”信息。这是一个例子;假设我有两个函数getThingIndex(uint64_t t)getThingAtIndex(uint64_t tidx)。第一个函数将参数视为thing 的编码,对索引进行非平凡的计算,然后返回它。然后可以通过调用getThingAtIndex 获得实际的“东西”。另一方面,getThingAtIndex 假设您正在查询结构并且已经有一个索引。这两种方法中的后者更快,但更重要的是,我想避免将thing 传递给getThingAtIndex 或将index 传递给getThingIndex 可能导致的头痛。

我正在考虑为 thing 创建类型和类似这样的事物索引:

struct Thing { uint64_t thing; }
struct ThingIndex { uint64_t idx; }

然后将上述函数的签名改为

getThingIndex(Thing t)
getThingAtIndex(ThingIndex idx)

现在,尽管 ThingThingIndex 编码相同 底层类型,但它们在编译时是不同的,我 通过传递索引来减少犯愚蠢错误的机会 getThingIndexgetThingAtIndex

但是,我担心这种方法的开销。功能 被调用了很多次(10s-100s 的数百万次),我很好奇是否 编译器将优化这些结构的创建,这些结构本质上是 除了编码编译时类型信息之外什么都不做。如果编译器不会 执行这样的优化,有没有办法创建这些类型的“丰富类型” 零开销?

【问题讨论】:

  • sizeof(Thing) == sizeof(uint64_t),这里有什么问题?
  • 我可能遗漏了一些东西,但是如果你传入 Thing 来查找,然后计算匹配 Thing 的索引,然后返回匹配 Thing,你不就只有 Thing 吗?我不知道您的设计或约束等,但似乎这可能更适合使用带有强类型 Thingstd:: 集合,也许是 std::set<Thing> 或类似的东西。
  • 好吧,您将按值传递这些参数,因此编译器应该为结构分配堆栈空间。如果结构与 unit64_t 大小相同,则不确定有多少开销。我将编译一些具有各种排列的代码,并查看生成的程序集列表以了解编译器在做什么。还可以运行一些计时基准。
  • @millsj,我知道大小是一样的;我的问题是关于运行时开销(即编译器会优化包含结构的构造)。
  • @pstrjds 约束是最初我必须处理从文件中读取的“事物”。但是,我已经构建了一个最小的完美哈希,以便我可以将每个“事物”分配给一个索引。所以,在初步计算出每个 Thing 的索引后,我想严格处理索引以避免重复查找开销。

标签: c++ optimization struct compile-time overhead


【解决方案1】:

看一下反汇编。

unsigned long long * x = new unsigned long long;
0110784E  push        8  
01107850  call        operator new (01102E51h)  
01107855  add         esp,4  
01107858  mov         dword ptr [ebp-0D4h],eax  
0110785E  mov         eax,dword ptr [ebp-0D4h]  
01107864  mov         dword ptr [x],eax  
*x = 5;
01107867  mov         eax,dword ptr [x]  
0110786A  mov         dword ptr [eax],5  
01107870  mov         dword ptr [eax+4],0  

还有结构体。

struct Thing { unsigned long long a; };
Thing * thing = new Thing;
0133784E  push        8  
01337850  call        operator new (01332E51h)  
01337855  add         esp,4  
01337858  mov         dword ptr [ebp-0D4h],eax  
0133785E  mov         eax,dword ptr [ebp-0D4h]  
01337864  mov         dword ptr [thing],eax  
thing->a = 5;
01337867  mov         eax,dword ptr [thing]  
0133786A  mov         dword ptr [eax],5  
01337870  mov         dword ptr [eax+4],0  

这两个指令没有区别。编译器并不关心this->a 是结构的成员,它访问它就像你刚刚声明了unsigned long long a

【讨论】:

  • 我明白了。出于好奇,你是怎么得到这么好看的拆解的?我想尝试相同的实验,除了变量是堆栈分配的而不是堆分配的。
  • 我使用 Visual Studio 生成了反汇编。调试时可以选择Debug -> Windows -> Disassembly
猜你喜欢
  • 2010-12-30
  • 1970-01-01
  • 2021-07-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-12-08
  • 2013-04-30
  • 2023-03-06
相关资源
最近更新 更多