以下是我的代码的一部分:(请注意,M
是一个很大的数字)
void myFunc(std::map<int, int>& myMap, int** arr) {
for (int i = 0; i < N; i++) {
for (int j = 0; j < M; j++) {
arr[i][j] = myMap[i] * j + i;
}
}
}
myMap[i]
是内循环中的循环不变量。所以我认为当我使用-O1
时,gcc会自动将其移出内循环。但它不起作用。因为我手动移动时如下:
void myFunc(std::map<int, int>& myMap, int** arr) {
for (int i = 0; i < N; i++) {
int tmp = myMap[i];
for (int j = 0; j < M; j++) {
arr[i][j] = tmp * j + i;
}
}
}
运行时比第一个版本好得多。
也许编译器认为myMap
会修改地图,所以它选择不进行优化。但我确信我只想阅读myMap
的值,不会修改它。如何让编译器理解?
答案 0 :(得分:0)
你是正确的,因为地图operator[]
总是返回一个值的可修改引用,所以编译器不能假定将它移到该内部循环之外是安全的。这是因为如果值不存在,操作员将插入值。哪个可能不你想要什么。
只需使用const
方法迭代地图即可轻松修复。您可以将地图作为myFunc
传递给const&
,然后使用cbegin()
和cend()
成员函数来获取对其中存储的值的引用。
E.g:
void myFunc(const std::map<int, int>& m, int** arr) {
int i = 0;
auto it = m.cbegin();
while (it != m.cend()) { // assumes m.size() == N
for (int j = 0; j < M; j++) {
arr[i][j] = (*it).second * j + i;
}
it++;
i++;
}
}
这是我的机器上的一些快速基准测试,适用于N=10
和M=1000000
。 (我跑了几次,这些都在中间的某个地方。)
您的原始版本:
real 0m0.449s
user 0m0.434s
sys 0m0.012s
你的第二个版本:
real 0m0.162s
user 0m0.148s
sys 0m0.012s
我的解决方案:
real 0m0.176s
user 0m0.162s
sys 0m0.012s
你的第二个解决方案实际上似乎总是快10%左右,所以如果你关心最后一点速度,那就自己提起这个任务。