是否允许编译器优化私有数据成员?

bit*_*ask 32 c++ optimization compilation language-lawyer

如果编译器可以证明一个类的(私有)成员从未被使用过,包括潜在的朋友,标准是否允许编译器从类的内存占用中删除这个成员?

不言而喻,这对于受保护或公共成员在编译时是不可能的,但在某些情况下,私有数据成员可能会构造这样的证明。


相关问题:

Pet*_*des 31

理论上可能(以及未使用的公共成员),但不是我们习惯的那种编译器生态系统(针对可以链接单独编译的代码的固定 ABI)。 删除未使用的成员只能通过禁止单独库1 的整个程序优化来完成

其他编译单元可能需要就 达成一致sizeof(foo),但.h如果它依赖于验证成员函数的行为的实现不依赖于任何私有成员,那么这将不是您可以从 a 派生的东西。

记住 C++ 只真正指定了一个程序,而不是一种做库的方法。ISO C++ 指定的语言与我们习惯的实现风格兼容(当然),但同时获取所有.cpp.h文件并生成单个自包含不可扩展可执行文件的实现是可能的。

如果您对实现进行了足够的约束(没有固定的 ABI),那么就可以在整个程序中积极应用 as-if 规则。


脚注 1:如果编译器已经可以看到类中声明的每个成员函数的定义,我将添加“或以某种方式将大小信息导出到其他正在编译的代码”作为允许库的一种方式。但@PasserBy 的回答指出,单独编译的库可能会以最终产生外部可见副作用(如 I/O)的方式使用声明的私有成员。所以我们必须完全排除它们。

鉴于此,公共成员和私有成员就此类优化而言是等效的。

  • @Joshua:像“write”或“read”这样带有“void*”或“char*”对象表示的I/O函数将是一个“使用”,因为它将是一个外部可观察的视图程序已存储在那里。 (2认同)

Kon*_*lph 18

如果编译器可以证明某个类的(私有)成员从未被使用过

编译器无法证明这一点,因为私有成员可以在其他编译单元中使用。具体来说,根据标准的[temp.spec]/6这在指向模板参数中成员的指针的上下文中是可能的,正如最初由 Johannes Schaub 所描述的

因此,总而言之:不,编译器不能优化私有数据成员,而不是优化公共或受保护成员(受 as-if 规则约束)。


Pas*_* By 12

不,因为您可以合法地破坏访问控制系统。

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
}
Run Code Online (Sandbox Code Playgroud)

考虑到编译器在A第一次使用时必须修复 ABI ,并且它永远无法知道某些未来的代码是否可以访问x,它必须修复A包含的内存x

  • ISO C++ 没有指定必须有 ABI。我添加了一个答案,指出不允许库的整个程序优化编译器理论上可以做到这一点,因为它知道它可以看到一切。不过,您的回答为允许单独编译库的编译器敲响了棺材。即我们实际想要使用的实现类型。 (5认同)
  • 在我的实验(C++17)中,您甚至根本不需要“tag”类型或“n”参数,这消除了警告。我不明白(也许你可以在你的答案中详细说明)为什么 `cheat&lt;&amp;A::x, 0&gt;` 甚至是合法的。 (3认同)