一、对比
C++11中引入了移动语义,用在资源频繁拷贝的地方。通过移动构造函数可以减少不必要的复制,带来性能上的提升。下面我们通过代码比较复制(拷贝)构造函数和移动构造函数的性能(速度)。
测试代码如下:
#include <iostream>
#include <memory>
#include <queue>
#include <string>
#include <chrono>
using namespace std;
class Person
{
private:
int age;
string name;
int* data;
public:
Person() : data(new int[1000000]) {}
~Person() { delete[] data; }
// 拷贝构造函数
Person(const Person& p) :
age(p.age),
name(),
data(new int[1000000]) {
std::copy(p.data, p.data + 1000000, data);
//cout << "Copy Constructor" << endl;
}
// 拷贝赋值运算符
Person& operator=(const Person& p) {
this->age = p.age;
this->name = ;
this->data = new int[1000000];
std::copy(p.data, p.data + 1000000, data);
//cout << "Copy Assign" << endl;
return *this;
}
// 移动构造函数
Person(Person&& p) :
age(std::move(p.age)),
name(std::move()),
data(p.data) {
p.data = nullptr; // 源对象的指针应该置空,以免源对象析构时影响本对象
//cout << "Move Constructor" << endl;
}
// 移动赋值运算符
Person& operator=(Person&& p) {
this->age = std::move(p.age);
this->name = std::move();
this->data = p.data;
p.data = nullptr;
//cout << "Move Assign" << endl;
return *this;
}
};
int main()
{
auto begin1 = std::chrono::high_resolution_clock::now();
queue<Person> queuePerson1;
for (int i = 0; i < 100; i++)
{
Person person;
queuePerson1.push(person);
}
//printf("入队列完毕\n");
for (int i=0; i< queuePerson1.size(); i++)
{
Person person = queuePerson1.front();
queuePerson1.pop();
}
//printf("出队列完毕\n");
auto end1 = std::chrono::high_resolution_clock::now();
auto elapsed1 = std::chrono::duration_cast<std::chrono::nanoseconds>(end1 - begin1);
printf("拷贝构造时间: %.3f seconds.\n", elapsed1.count() * 1e-9);
auto begin2 = std::chrono::high_resolution_clock::now();
queue<Person> queuePerson2;
for (int i = 0; i < 100; i++)
{
Person person;
queuePerson2.push(std::move(person));
}
//printf("入队列完毕\n");
for (int i = 0; i < queuePerson2.size(); i++)
{
Person person = std::move(queuePerson2.front());
queuePerson2.pop();
}
//printf("出队列完毕\n");
auto end2 = std::chrono::high_resolution_clock::now();
auto elapsed2 = std::chrono::duration_cast<std::chrono::nanoseconds>(end2 - begin2);
printf("移动构造时间: %.3f seconds.\n", elapsed2.count() * 1e-9);
return 0;
}
在Visual Studio中选择release模式,编译执行效果如下:
可以看到使用移动构造函数Person(Person&& p) 速度比使用拷贝构造函数Person(const Person& p)快200多倍。所以我们尽可能使用移动构造函数代替拷贝构造函数(这里又会涉及到亡值的问题需要注意),比如生产者消费者模式的入队列、出队列操作,我们可以使用移动构造来提示性能。
二、测量执行时间的方法优化
可以根据我另一篇文章《C++计算打印函数和代码块的执行时间(支持所有类型函数)》中的
measure函数对测量方法进行优化。优化后代码如下:
#include <thread>
#include <memory>
#include <future>
#include <functional>
#include <chrono>
#include <iostream>
#include <queue>
#include <string>
using namespace std;
template<class T, class... Args>
auto measure(T&& func, Args&&... args)->std::future<typename std::result_of<T(Args...)>::type>
{
using return_type = typename std::result_of<T(Args...)>::type;
auto task = std::make_shared<std::packaged_task<return_type()>>
(std::bind(std::forward<T>(func), std::forward<Args>(args)...));
std::future<return_type> res = task->get_future();
auto begin = std::chrono::high_resolution_clock::now();
(*task)();
auto end = std::chrono::high_resolution_clock::now();
auto elapsed = std::chrono::duration_cast<std::chrono::nanoseconds>(end - begin);
printf("执行时间: % .3f seconds.\n", elapsed.count() * 1e-9);
return res;
}
class Person
{
private:
int age;
string name;
int* data;
public:
Person() : data(new int[1000000]) {}
~Person() { delete[] data; }
// 拷贝构造函数
Person(const Person& p) :
age(p.age),
name(),
data(new int[1000000]) {
std::copy(p.data, p.data + 1000000, data);
//cout << "Copy Constructor" << endl;
}
// 拷贝赋值运算符
Person& operator=(const Person& p) {
this->age = p.age;
this->name = ;
this->data = new int[1000000];
std::copy(p.data, p.data + 1000000, data);
//cout << "Copy Assign" << endl;
return *this;
}
// 移动构造函数
Person(Person&& p) :
age(std::move(p.age)),
name(std::move()),
data(p.data) {
p.data = nullptr; // 源对象的指针应该置空,以免源对象析构时影响本对象
//cout << "Move Constructor" << endl;
}
// 移动赋值运算符
Person& operator=(Person&& p) {
this->age = std::move(p.age);
this->name = std::move();
this->data = p.data;
p.data = nullptr;
//cout << "Move Assign" << endl;
return *this;
}
};
int main() {
measure([]{
queue<Person> queuePerson1;
for (int i = 0; i < 100; i++)
{
Person person;
queuePerson1.push(person);
}
//printf("入队列完毕\n");
for (int i = 0; i < queuePerson1.size(); i++)
{
Person person = queuePerson1.front();
queuePerson1.pop();
}
});
measure([] {
queue<Person> queuePerson2;
for (int i = 0; i < 100; i++)
{
Person person;
queuePerson2.push(std::move(person));
}
//printf("入队列完毕\n");
for (int i = 0; i < queuePerson2.size(); i++)
{
Person person = std::move(queuePerson2.front());
queuePerson2.pop();
}
//printf("出队列完毕\n");
});
return 0;
}
参考:《C++笔记 · 右值引用,移动语义,移动构造函数和移动赋值运算符》