代码

#include <QHash>
#include <QSharedPointer>
#include <chrono>
#include <functional>
#include <iostream>
#include <memory>
#include <optional>
using namespace std;
using namespace std::chrono;

#define COUNT 10000000

//#define TEST_0_CALL
//#define TEST_0_TEMP_CALL
#define TEST_I_CALL
//#define TEST_I_TEMP_CALL

#define PARAMS_DEFINE QString, int, bool, QHash<int, QString>
#define PARAMS_VALUE "", 1, false, QHash<int, QString>()

//#define PARAMS_DEFINE
//#define PARAMS_VALUE

typedef function<void(PARAMS_DEFINE)> TestFunc;

static int v = 0;

void test(PARAMS_DEFINE) {
    int a = v + 1;
    int b = a + 2;
}

static std::optional<TestFunc> normal = test;
static std::optional<QSharedPointer<TestFunc>> pt = QSharedPointer<TestFunc>(new TestFunc(test));
static QHash<int, std::optional<TestFunc>> normalVector;
static QHash<int, std::optional<QSharedPointer<TestFunc>>> ptVector;

std::optional<TestFunc> getNormal(qint32 idx) { return normalVector.value(idx); }

std::optional<QSharedPointer<TestFunc>> getPt(qint32 idx) { return ptVector.value(idx); }

void runNormal() {
    auto m1 = duration_cast<microseconds>(system_clock::now().time_since_epoch()).count();

    for (int i = 0; i < COUNT; ++i) {
        // 1. 取0直接调用
#ifdef TEST_0_CALL
        getNormal(0).value()(PARAMS_VALUE);
#endif

// 2. 取0赋值调用
#ifdef TEST_0_TEMP_CALL
        auto temp = getNormal(0);
        temp.value()(PARAMS_VALUE);
#endif
// 3.取索引直接调用
#ifdef TEST_I_CALL
        getNormal(i).value()(PARAMS_VALUE);
#endif

// 4.取索引赋值调用
#ifdef TEST_I_TEMP_CALL
        auto temp1 = getNormal(i);
        temp1.value()(PARAMS_VALUE);
#endif
    }

    auto m2 = duration_cast<microseconds>(system_clock::now().time_since_epoch()).count();
    cout << m2 - m1 << endl;
}

void runSP() {
    auto m1 = duration_cast<microseconds>(system_clock::now().time_since_epoch()).count();

    for (int i = 0; i < COUNT; ++i) {
        // 1. 取0直接调用
#ifdef TEST_0_CALL
        (*getPt(0).value())(PARAMS_VALUE);
#endif

// 2. 取0赋值调用
#ifdef TEST_0_TEMP_CALL
        auto temp = getPt(0);
        (*temp.value())(PARAMS_VALUE);
#endif
// 3.取索引直接调用
#ifdef TEST_I_CALL
        (*getPt(i).value())(PARAMS_VALUE);
#endif

// 4.取索引赋值调用
#ifdef TEST_I_TEMP_CALL
        auto temp1 = getPt(i);
        (*temp1.value())(PARAMS_VALUE);
#endif
    }

    auto m2 = duration_cast<microseconds>(system_clock::now().time_since_epoch()).count();
    cout << m2 - m1 << endl;
}

int main(int argc, char** argv) {
    for (int i = 0; i < COUNT; ++i) {
        normalVector.insert(i, normal);
        ptVector.insert(i, pt);
    }

    runNormal();
    runSP();
    return 0;
}

分析

debug

调用0的情况下,编译器不做临时变量优化,不做std::function优化,此时普通变量多构造std::function性能损耗,调用智能指针多间接调用性能损耗,所以智能指针略优于普通变量

image.png

调用i的情况下,与0类似

image.png

release

调用0,函数参数简单情况下,编译器做临时变量优化,做std::function优化,此时普通变量构造一次std::function,智能指针多间接调用性能损耗,所以普通变量优于智能指针

image.png

调用i,函数参数简单情况下,编译器做std::function优化,普通变量构造std::function,智能指针间接调用,由于参数简单,std::function更快,所以普通变量略优于智能指针

image.png

调用i,函数参数复杂情况下,编译器做std::function优化,普通变量构造std::function,智能指针间接调用,由于参数复杂,std::function慢,所以智能指针略优于普通变量

image.png


点墨
26 声望3 粉丝

全栈前端开发工程师