编译器
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平台
一百万条数据情况下,使用非指针型变量,通过移动构造函数,需要大概1s左右进行vector内容拷贝,使用指针型变量,通过移动构造函数(只拷贝指针地址),则没有拷贝性能损耗。
linux平台(开启elide优化)
两者性能一致,经过elide优化后,只有一次构造,两者性能一致。
linux平台(关闭elide优化)
使用-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;
}
运行结果
使用QT的QList的时候,行为与指针型移动构造一致,无性能损耗。
结论
在使用STL容器,比如vector,list等,直接返回局部变量会有性能损耗,建议使用智能指针,或者传递指针进来进行修改。
在使用QT容器,比如QVector,QList等,直接返回局部变量不会有性能损耗,建议直接返回即可。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。