C++复制构造函数和移动构造函数的性能速度对比

一、对比

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(p.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 = p.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(p.name)),
        data(p.data) {
        p.data = nullptr; // 源对象的指针应该置空,以免源对象析构时影响本对象
        //cout << "Move Constructor" << endl;
    }

    // 移动赋值运算符
    Person& operator=(Person&& p) {
        this->age = std::move(p.age);
        this->name = std::move(p.name);
        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(p.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 = p.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(p.name)),
        data(p.data) {
        p.data = nullptr; // 源对象的指针应该置空,以免源对象析构时影响本对象
        //cout << "Move Constructor" << endl;
    }

    // 移动赋值运算符
    Person& operator=(Person&& p) {
        this->age = std::move(p.age);
        this->name = std::move(p.name);
        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++笔记 · 右值引用,移动语义,移动构造函数和移动赋值运算符

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值