【c++】右值引用,左值引用与move

参考一篇不错的博文

核心思想:

临时对象被使用完之后会被立即析构,在析构函数中free掉申请的内存资源。
如果能够直接使用临时对象已经申请的资源,并在其析构函数中取消对资源的释放,这样既能节省资源,又能节省资源申请和释放的时间。 这正是定义移动语义的目的。

简单来说,类的构造函数、使用左值引用的构造函数、operator=重载函数等,会申请新的内存,复制数据;而使用右值引用的这些函数中,则直接使用原有的内存,并保证原有内存不被释放,这样就节省了一部分时间,提高了swap等函数的效率。

在使用自定义类时,用户可以根据需求选择左值引用还是右值引用,而选择右值引用带来的性能提升则取决于类函数的写法了。例如,使用vector的左值引用与右值引用几乎没有差别,而下面的例子使用右引则快了很多。

std::move函数就是将左引转换为右引。

上代码:

#include <iostream>
#include <vector>
using namespace std;

class MyString
{
public:
    MyString()
    {
        m_data = NULL;
        m_len = 0;
    }

    MyString(const char* s)
    {
        m_len = strlen(s);
        init_data(s);
        cout << "构造函数" << s << endl;
    }

    MyString(const MyString& str)
    {
        m_len = str.m_len;
        init_data(str.m_data);
        cout << "拷贝构造函数" << str.m_data << endl;
    }

    MyString(MyString&& str)
    {
        cout << "移动构造函数" << str.m_data << endl;
        m_len = str.m_len;
        m_data = str.m_data;
        str.m_len = 0;
        str.m_data = NULL;// 防止在析构函数中将内存释放掉       
    }

    MyString& operator=(const MyString& str)
    {
        if (this != &str) {
            this->m_len = str.m_len;
            init_data(str.m_data);
        }
        cout << "等号操作符重载" << str.m_data << endl;
        return *this;
    }

    MyString& operator=(MyString&& str)
    {
        cout << "移动等号操作符重载" << str.m_data << endl;
        if (this != &str) {
            this->m_len = str.m_len;
            this->m_data = str.m_data;
            str.m_len = 0;
            str.m_data = NULL;// 防止在析构函数中将内存释放掉  
        }
        return *this;
    }

    ~MyString()
    {
        if (m_data != NULL) {
            cout << "析构函数" << endl;
            free(m_data);
        }
    }

private:
    void init_data(const char* s)
    {
        m_data = new char[m_len + 1];
        memcpy(m_data, s, m_len);
        m_data[m_len] = '\0';
    }
    char* m_data;
    size_t m_len;
};

namespace MyT {
    template <class T>
    void swapWithMove(T& a, T& b)
    {
        T tmp(std::move(a));// move a to tmp
        a = std::move(b);// move b to a
        b = std::move(tmp);//move tmp to b
    }

    template<class T>
    void swap(T& a, T& b) {
        T temp = a;
        a = b;
        b = temp;
    }
}

void test()
{
    MyString a("hello");
    MyString b("world");
    int n = 200;
    clock_t t0 = clock();
    for (int i = 0; i < n; i++)
    {
        MyT::swap<MyString>(a, b);
    }
    clock_t t1 = clock();
    for (int i = 0; i < n; i++)
    {
        MyT::swapWithMove<MyString>(a, b);
    }
    cout << t1 - t0 << endl;
    cout << clock() - t1 << endl;
}

int main()
{
    test();
    return 0;
}

运行结果:
在这里插入图片描述
可以看到使用右引的swap函数要比使用左引快了1/6。这是由于使用左引的构造函数、operator=函数中调用了init_data(),进行了字符串的拷贝,而右引时省去了这一操作。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值