重要的是要认识到编译器生成的代码对您的数据结构没有实际的了解(因为这样的东西在汇编级别上不存在),优化器也没有。编译器仅为每个函数生成代码,而不为数据结构生成代码。
好的,它还会写入常量数据段等。
基于此,我们已经可以说优化器不会“删除”或“消除”成员,因为它不会输出数据结构。它输出可能不使用成员的代码,其目标之一是通过消除成员的无意义使用(即写入/读取)来节省内存或周期。
其要点是,“如果编译器可以证明在函数范围内(包括内联到该函数中的函数),未使用的成员对该函数的操作方式(及其返回的内容)没有影响,那么机会就在于成员的存在不会引起任何开销”。
当您使函数与外界的交互对于编译器而言更加复杂/不清楚时(采用/返回更复杂的数据结构,例如a std::vector<Foo>
,将函数的定义隐藏在不同的编译单元中,禁止/取消内联等)。 ,编译器无法证明未使用的成员无效的可能性越来越大。
这里没有硬性规则,因为这完全取决于编译器所做的优化,但是,只要您做一些琐碎的事情(例如YSC的答案中所示),就很可能不会出现开销,而做复杂的事情(例如,返回一个std::vector<Foo>
从过大的内联函数)可能会招致的开销。
为了说明这一点,请考虑以下示例:
struct Foo {
int var1 = 3;
int var2 = 4;
int var3 = 5;
};
int test()
{
Foo foo;
std::array<char, sizeof(Foo)> arr;
std::memcpy(&arr, &foo, sizeof(Foo));
return arr[0] + arr[4];
}
我们在这里做了一些琐碎的事情(从字节表示中获取地址,检查并添加字节),但是优化器可以确定在该平台上结果始终是相同的:
test(): # @test()
mov eax, 7
ret
成员Foo
不仅不占用任何内存,Foo
甚至都不存在!如果还有其他无法优化的用法,则sizeof(Foo)
可能很重要-但仅适用于该段代码!如果可以像这样优化所有用法,则例如的存在var3
不会影响所生成的代码。但是,即使在其他地方使用它,test()
也将保持最佳状态!
简而言之:的每种用法Foo
都是独立优化的。由于不需要成员,有些可能会使用更多的内存,有些可能不会。有关更多详细信息,请查阅您的编译器手册。