链接操作符时的编译器优化

Compiler optimization when chaining operators

本文关键字:编译器 优化 操作符 链接      更新时间:2023-10-16

我重载了std::vector上的算术/赋值运算符,以便能够进行一些基本的线性代数运算。但是,当链接这些操作时,我遇到了一些性能问题。

这是我的main.h的内容:

#include <vector>
#include <stdlib.h>
using namespace std;
typedef vector<float> vec;
inline vec& operator+=(vec& lhs, const vec& rhs) {
    for (size_t i = 0; i < lhs.size(); ++i) {
        lhs[i] += rhs[i];
    }
    return lhs;
}
inline vec operator*(float lhs, vec rhs) {
    for (size_t i = 0; i < rhs.size(); ++i) {
        rhs[i] *= lhs;
    }
    return rhs;
}

main1.cpp含量:

#include "main.h"
// gcc 4.9.2 (-O3): 0m5.965s
int main(int, char**) {
    float x = rand();
    vec v1(1000);
    vec v2(1000);
    for (size_t i = 0; i < v1.size(); ++i) {
        v1[i] = rand();
        v2[i] = rand();
    }
    for (int i = 0; i < 10000000; ++i) {
        v1 += x * v2;
        // same as:
        //vec y = x * v2;
        //v1 += y;
    }
    return 0;
}

main2.cpp含量:

#include "main.h"
// gcc 4.9.2 (-O3): 0m2.400s
int main(int, char**) {
    // same stuff
    for (int i = 0; i < 10000000; ++i) {
        for (size_t j = 0; j < v1.size(); ++j) {
            v1[j] += x * v2[j];
        }
    }
    return 0;
}

第二个程序比第一个程序运行得快得多。我确实理解为什么会这样:第一个程序不是只有一个循环,而是进行了两个循环,并分配了一个临时vector。

但这是我希望编译器看到和优化的那种东西。还是我做错了什么?

我不记得在线性代数库(例如Armadillo)中遇到过这个问题。他们如何解决这个问题?这是否涉及一些复杂的模板编程,或者有一些简单的方法来帮助编译器优化它?

有一些非常丑陋的模板元编程解决方案来解决这个问题。但是后来标准委员会发明了右值引用和移动语义的组合。查找这些,并找到许多解决方案的示例,而不需要荒谬的元编程级别。