c++ - 如何让 MSVC 编译器优化多步 POD 初始化?
问题描述
我制作了这个示例代码:
#include <vector>
struct POD {
int a;
int b;
int c;
inline static POD make_pod_with_default()
{
POD p{ 41, 51, 61 };
return p;
}
inline void change_pod_a(POD &p, int a) {
p.a = a;
}
inline void change_pod_b(POD &p, int b) {
p.b = b;
}
static POD make_pod_with_a(int a) {
POD p = make_pod_with_default();
p.change_pod_a(p, a);
return p;
}
static POD make_pod_with_b(int a) {
POD p = make_pod_with_default();
p.change_pod_b(p, a);
return p;
}
};
int main()
{
std::vector<POD> vec{};
vec.reserve(2);
vec.push_back(POD::make_pod_with_a(71));
vec.push_back(POD::make_pod_with_b(81));
return vec[0].a + vec[0].b + vec[0].c + vec[1].a + vec[1].b + vec[1].c;
}
在编译的汇编代码中,我们可以看到正在为第一个 vec.push_back(...) 调用生成以下指令:
...
mov DWORD PTR $T2[esp+32], 41 ; 00000029H
...
mov DWORD PTR $T2[esp+36], 51 ; 00000033H
...
mov DWORD PTR $T5[esp+32], 71 ; 00000047H
...
mov DWORD PTR $T6[esp+44], 61 ; 0000003dH
...
71 有一个 mov to [esp+32] ,但是 41 的 mov 到 [esp+32] 仍然存在,没用!我怎样才能为 MSVC 编写能够实现这种优化的代码,MSVC 甚至有能力吗?
GCC 和 CLANG 都提供了更优化的版本,但是 CLANG 以非常干净和合乎逻辑的方式在几乎没有开销的情况下大幅失败:
CLANG 生成的代码:
main: # @main
push rax
mov edi, 24
call operator new(unsigned long)
mov rdi, rax
call operator delete(void*)
mov eax, 366
pop rcx
ret
一切都是在编译时完成的 71 + 51 + 61 + 41 + 81 + 61 = 366!我必须承认,看到我的程序在编译时被计算并且仍然在程序集中对 vec.reserve() 的调用很痛苦……但是到目前为止,CLANG 仍然占了上风!加油 MSVC,这不是 volatile 的向量。
解决方案
如果你打开你的方法constexpr
,你可能会这样做:
constexpr POD step_one()
{
POD p{2, 5, 11};
p.b = 3;
return p;
}
constexpr void step_two(POD &p)
{
p.c = 5;
}
constexpr POD make_pod(){
POD p = step_one();
step_two(p);
return p;
}
POD make_pod_final()
{
constexpr POD res = make_pod();
return res;
}
结果:
make_pod_final PROC
mov eax, DWORD PTR $T1[esp-4]
mov DWORD PTR [eax], 2
mov DWORD PTR [eax+4], 3
mov DWORD PTR [eax+8], 5
ret 0
推荐阅读
- angular - Angular从完整路径获取不带扩展名的文件名
- java - 使用java 8根据该对象的可为空的ArrayList属性对对象列表进行排序
- asp.net - 负载均衡器后面的 Identity Server 4 给出未经授权的异常
- sqlite - Sqlite 从 3 个连接表中删除所有连接的行
- c - 是否有任何方法可以在 VScode 上停止此消息(突然停止)
- javascript - 将当前日期添加到 pdf(在浏览器中打开时)
- android - 如何为垂直搜索栏应用垂直进度可绘制
- javascript - cypress 中命令断言失败时如何在重试逻辑中添加延迟
- r - 根据时间步长对数据进行排序?
- c++ - CMake连接到数组中的每个字符串