是否允许编译器优化私有数据成员?
如果编译器可以证明一个类的(私有)成员从未被使用过,包括潜在的朋友,标准是否允许编译器从类的内存占用中删除这个成员?
不言而喻,这对于受保护或公共成员在编译时是不可能的,但在某些情况下,私有数据成员可能会构造这样的证明。
相关问题:
- public、private 和protected 的幕后(引发这个问题)
- 是否允许 C++ 编译器优化未引用的本地对象(关于自动对象)
- 静态变量总是会耗尽内存吗?(关于静态对象)
回答
理论上可能(以及未使用的公共成员),但不是我们习惯的那种编译器生态系统(针对可以链接单独编译的代码的固定 ABI)。 删除未使用的成员只能通过禁止单独库1 的整个程序优化来完成。
其他编译单元可能需要就 达成一致sizeof(foo),但.h如果它依赖于验证成员函数的行为的实现不依赖于任何私有成员,那么这将不是您可以从 a 派生的东西。
记住 C++ 只真正指定了一个程序,而不是一种做库的方法。ISO C++ 指定的语言与我们习惯的实现风格兼容(当然),但同时获取所有.cpp和.h文件并生成单个自包含不可扩展可执行文件的实现是可能的。
如果您对实现进行了足够的约束(没有固定的 ABI),那么就可以在整个程序中积极应用 as-if 规则。
脚注 1:如果编译器已经可以看到类中声明的每个成员函数的定义,我将添加“或以某种方式将大小信息导出到其他正在编译的代码”作为允许库的一种方式。但@PasserBy 的回答指出,单独编译的库可能会以最终产生外部可见副作用(如 I/O)的方式使用声明的私有成员。所以我们必须完全排除它们。
鉴于此,公共成员和私有成员就此类优化而言是等效的。
- @Joshua: An I/O function like `write` or `read` with a `void*` or `char*` to the object representation would be a "use", because it would be an externally-observable view of whatever the program had stored there.
回答
如果编译器可以证明某个类的(私有)成员从未被使用过
编译器无法证明这一点,因为私有成员可以在其他编译单元中使用。具体来说,根据标准的[temp.spec]/6,这在指向模板参数中成员的指针的上下文中是可能的,正如最初由 Johannes Schaub 所描述的。
因此,总而言之:不,编译器不能优化私有数据成员,而不是优化公共或受保护成员(受 as-if 规则约束)。
回答
不,因为您可以合法地破坏访问控制系统。
class A
{
int x;
};
auto f();
template<auto x>
struct cheat
{
friend auto f() { return x; }
};
template struct cheat<&A::x>; // see [temp.spec]/6
int& foo(A& a)
{
return a.*f(); // returns a.x
}
考虑到编译器在A第一次使用时必须修复 ABI ,并且它永远无法知道某些未来的代码是否可以访问x,它必须修复A包含的内存x。
- ISO C++ doesn't specify that there has to be an ABI. I added an answer that points out that a whole-program optimizing compiler that doesn't allow libraries could do this in theory, because it knows it's seeing everything. Your answer puts the nail in the coffin for compilers that allow separately-compiled libraries, though. i.e. the kind of implementations we actually want to use.
- It seems that you don't even need the `tag` type or `n` parameter at all in my experiments (C++17) which gets rid of a warning. What I don't understand (and perhaps you could elaborate in your answer) why `cheat<&A::x, 0>` is even legal.