为什么编译器不能优化未使用的 static std::string?

Vem*_*ulo 7 c++ static-constructor compiler-optimization

如果我使用 GCC 或 Clang 编译此代码并启用-O2优化,我仍然会得到一些全局对象初始化。任何代码是否有可能访问这些变量?

#include <string>
static const std::string s = "";

int main() { return 0; }
Run Code Online (Sandbox Code Playgroud)

编译器输出:

main:
        xor     eax, eax
        ret
_GLOBAL__sub_I_main:
        mov     edx, OFFSET FLAT:__dso_handle
        mov     esi, OFFSET FLAT:s
        mov     edi, OFFSET FLAT:_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEED1Ev
        mov     QWORD PTR s[rip], OFFSET FLAT:s+16
        mov     QWORD PTR s[rip+8], 0
        mov     BYTE PTR s[rip+16], 0
        jmp     __cxa_atexit
Run Code Online (Sandbox Code Playgroud)

具体来说,我没想到这个_GLOBAL__sub_I_main:部分。

神箭链接

编辑:即使使用简单的自定义类型,编译器仍然会生成一些代码。

class Aloha
{
public:
    Aloha () : i(1) {}
    ~Aloha() = default;
private:
    int i;
};
static const Aloha a;
int main() { return 0; }
Run Code Online (Sandbox Code Playgroud)

编译器输出:

main:
        xor     eax, eax
        ret
_GLOBAL__sub_I_main:
        ret
Run Code Online (Sandbox Code Playgroud)

Swi*_*Pie 2

使用短字符串优化 (SSO) 编译该代码可能相当于获取 的std::string成员变量的地址。构造函数必须在编译时分析字符串长度,并选择它是否适合std::string对象的内部存储,或者必须动态分配内存,但随后发现它从未被读取,因此可以优化分配代码。

在这种情况下,缺乏优化可能是一种优化缺陷,仅限于像这样的简单外围示例:

const int i = 3;

int main()
{
    return (long long)(&i);  // to make sure that address was used
}
Run Code Online (Sandbox Code Playgroud)

GCC生成代码:

i:
        .long   3     ; this a variable
main:
        push    rbp
        mov     rbp, rsp
        mov     eax, OFFSET FLAT:i
        pop     rbp
        ret
Run Code Online (Sandbox Code Playgroud)

GCC 也不会优化这段代码:

const int i = 3;
const int *p = &i;
int main() {  return 0; }
Run Code Online (Sandbox Code Playgroud)

在文件作用域中声明的静态变量,尤其是 const 限定的变量,可以根据 as-if 规则进行优化,除非 使用了它们的地址,GCC 只对 const 限定的变量执行此操作,无论用例如何。获取变量的地址是一种可观察的行为,因为它可以传递到某个地方。追踪的逻辑太复杂而难以实现,并且没有什么实际价值。

当然,不使用地址的代码

const int i = 3;
int main() { return i; }
Run Code Online (Sandbox Code Playgroud)

优化保留存储的结果:

main:
    mov     eax, 3
    ret
Run Code Online (Sandbox Code Playgroud)

从 C++20 constexpr 构造std::string? 根据旧规则,如果结果依赖于参数,则它不能是编译时表达式。std::string如果字符串太长,可能会动态分配内存,这不是编译时操作。看来,在某些情况下,目前唯一支持 C++20 所需功能的主流编译器是 MSVC。