1

编译器

windows平台: Microsoft Visual C++ Compiler 16.10.31321.278 (amd64) vs2019
linux平台:gcc version 8.5.0 20210514 (Red Hat 8.5.0-3) (GCC)

编译器优化

Test test(){
    Test a; //A
    return a;//B
}
int main(){
    Test b = test();//C
    return 0;
}

windows平台下,编译器会优化掉C,进行A构造,B移动构造/拷贝构造(有移动构造下使用移动构造)

linux平台下,开启elide优化,编译器会优化掉B和C,只进行A构造

linux平台下,关闭elide优化,编译器不进行优化,会进行A构造,B移动构造/拷贝构造(有移动构造下使用移动构造),C移动构造/拷贝构造(有移动构造下使用移动构造)

vector

代码

#include <iostream>
#include <chrono>
#include <vector>

using namespace std;

static int COUNT = 1000000;

class BigObject {
public:
    int i = 10;
    string v = "test";
    float f = 10.00;
};

class TestNotP {
public:
    TestNotP() {
        cout << "constructor" << endl;
    }
    ~TestNotP() { cout << "~constructor" << endl; }
    TestNotP(const TestNotP& other) {
        cout << "copy constructor" << endl;
        v = other.v;
    }
    TestNotP& operator=(const TestNotP& other) {
        if (this != &other) {
            cout << "copy constructor =" << endl;
            v = other.v;
        }
        return *this;
    }
    TestNotP(TestNotP&& other) {
        cout << "move constructor" << endl;
        this->v = other.v;
        other.v = vector<BigObject>();
    }
    TestNotP& operator=(TestNotP&& other) {
        cout << "move constructor =" << endl;
        if (this != &other) {
            this->v = other.v;
            other.v = vector<BigObject>();
        }
        return *this;
    }
    void printVAddr() {
        cout << "v's addr:" << &v << endl;
    }
    void init() {
        for (int i = 0; i < COUNT; ++i) {
            BigObject obj;
            v.push_back(obj);
        }
    }
    vector<BigObject> v;
};

class TestP {
public:
    TestP() {
        cout << "constructor" << endl;
        vp = new vector<BigObject>();
    }
    ~TestP() {
        cout << "~constructor" << endl;
        delete vp;
    }
    TestP(const TestP& other) {
        cout << "copy constructor" << endl;
        vp = new vector<BigObject>(*other.vp);
    }
    TestP& operator=(const TestP& other) {
        if (this != &other) {
            cout << "copy constructor =" << endl;
            delete vp;
            vp = new vector<BigObject>(*other.vp);
        }
        return *this;
    }
    TestP(TestP&& other) {
        cout << "move constructor" << endl;
        this->vp = other.vp;
        other.vp = nullptr;
    }
    TestP& operator=(TestP&& other) {
        cout << "move constructor =" << endl;
        if (this != &other) {
            delete this->vp;
            this->vp = other.vp;
            other.vp = nullptr;
        }
        return *this;
    }
    void printVAddr() {
        cout << " vp's addr:" << vp << endl;
    }
    void init() {
        for (int i = 0; i < COUNT; ++i) {
            BigObject obj;
            vp->push_back(obj);
        }
    }
    vector<BigObject>* vp;
};


TestNotP test1() {
    TestNotP t;
    auto now = std::chrono::system_clock::now();
    t.init();
    auto later = std::chrono::system_clock::now();
    cout << "constructor time: " << std::chrono::duration_cast<std::chrono::milliseconds>(later - now).count() << " ms" << std::endl;
    return t;
}

TestP test2() {
    TestP t;
    auto now = std::chrono::system_clock::now();
    t.init();
    auto later = std::chrono::system_clock::now();
    cout << "constructor time: " << std::chrono::duration_cast<std::chrono::milliseconds>(later - now).count() << " ms" << std::endl;
    return t;
}

int main() {

    auto now = std::chrono::system_clock::now();

    //handle TestNotP
    TestNotP p1 = test1();

    auto later = std::chrono::system_clock::now();

    cout << "NotP time: " << std::chrono::duration_cast<std::chrono::milliseconds>(later - now).count() << " ms" << std::endl;

    auto now1 = std::chrono::system_clock::now();

    //handle TestP
    TestP p2 = test2();

    auto later1 = std::chrono::system_clock::now();

    cout << "P time: " << std::chrono::duration_cast<std::chrono::milliseconds>(later1 - now1).count() << " ms" << std::endl;


    return 0;
}

运行结果

window平台

image.png

一百万条数据情况下,使用非指针型变量,通过移动构造函数,需要大概1s左右进行vector内容拷贝,使用指针型变量,通过移动构造函数(只拷贝指针地址),则没有拷贝性能损耗。

linux平台(开启elide优化)

image.png

两者性能一致,经过elide优化后,只有一次构造,两者性能一致。

linux平台(关闭elide优化)

image.png

使用-fno-elide-constructors关闭编译器优化,会进行两次移动构造,非指针型变量需要拷贝vector,指针型变量则只需要拷贝vector指针的地址,性能上指针型更优。

QList

代码

#include <iostream>
#include <chrono>
#include <QList>

using namespace std;

static int COUNT = 1000000;

class BigObject {
public:
    int i = 10;
    string v = "test";
    float f = 10.00;
};

class TestNotP {
public:
    TestNotP() {
        cout << "constructor" << endl;
    }
    ~TestNotP() { cout << "~constructor" << endl; }
    TestNotP(const TestNotP& other) {
        cout << "copy constructor" << endl;
        v = other.v;
    }
    TestNotP& operator=(const TestNotP& other) {
        if (this != &other) {
            cout << "copy constructor =" << endl;
            v = other.v;
        }
        return *this;
    }
    TestNotP(TestNotP&& other) {
        cout << "move constructor" << endl;
        this->v = other.v;
        other.v = QList<BigObject>();
    }
    TestNotP& operator=(TestNotP&& other) {
        cout << "move constructor =" << endl;
        if (this != &other) {
            this->v = other.v;
            other.v = QList<BigObject>();
        }
        return *this;
    }
    void printVAddr() {
        cout << "v's addr:" << &v << endl;
    }
    void init() {
        for (int i = 0; i < COUNT; ++i) {
            BigObject obj;
            v.push_back(obj);
        }
    }
    QList<BigObject> v;
};

class TestP {
public:
    TestP() {
        cout << "constructor" << endl;
        vp = new QList<BigObject>();
    }
    ~TestP() {
        cout << "~constructor" << endl;
        delete vp;
    }
    TestP(const TestP& other) {
        cout << "copy constructor" << endl;
        vp = new QList<BigObject>(*other.vp);
    }
    TestP& operator=(const TestP& other) {
        if (this != &other) {
            cout << "copy constructor =" << endl;
            delete vp;
            vp = new QList<BigObject>(*other.vp);
        }
        return *this;
    }
    TestP(TestP&& other) {
        cout << "move constructor" << endl;
        this->vp = other.vp;
        other.vp = nullptr;
    }
    TestP& operator=(TestP&& other) {
        cout << "move constructor =" << endl;
        if (this != &other) {
            delete this->vp;
            this->vp = other.vp;
            other.vp = nullptr;
        }
        return *this;
    }
    void printVAddr() {
        cout << " vp's addr:" << vp << endl;
    }
    void init() {
        for (int i = 0; i < COUNT; ++i) {
            BigObject obj;
            vp->push_back(obj);
        }
    }
    QList<BigObject>* vp;
};


TestNotP test1() {
    TestNotP t;
    auto now = std::chrono::system_clock::now();
    t.init();
    auto later = std::chrono::system_clock::now();
    cout << "constructor time: " << std::chrono::duration_cast<std::chrono::milliseconds>(later - now).count() << " ms" << std::endl;
    return t;
}

TestP test2() {
    TestP t;
    auto now = std::chrono::system_clock::now();
    t.init();
    auto later = std::chrono::system_clock::now();
    cout << "constructor time: " << std::chrono::duration_cast<std::chrono::milliseconds>(later - now).count() << " ms" << std::endl;
    return t;
}

int main() {

    auto now = std::chrono::system_clock::now();

    //handle TestNotP
    TestNotP p1 = test1();

    auto later = std::chrono::system_clock::now();

    cout << "NotP time: " << std::chrono::duration_cast<std::chrono::milliseconds>(later - now).count() << " ms" << std::endl;

    auto now1 = std::chrono::system_clock::now();

    //handle TestP
    TestP p2 = test2();

    auto later1 = std::chrono::system_clock::now();

    cout << "P time: " << std::chrono::duration_cast<std::chrono::milliseconds>(later1 - now1).count() << " ms" << std::endl;


    return 0;
}

运行结果

image.png

使用QT的QList的时候,行为与指针型移动构造一致,无性能损耗。

结论

在使用STL容器,比如vector,list等,直接返回局部变量会有性能损耗,建议使用智能指针,或者传递指针进来进行修改。
在使用QT容器,比如QVector,QList等,直接返回局部变量不会有性能损耗,建议直接返回即可。


点墨
26 声望3 粉丝

全栈前端开发工程师