C++的移动语义

在C++中对于一个对象的复制有多种方法,其中常用的有拷贝构造函数或者采用重构赋值法。
拷贝构造函数(copy constructor):

#include<iostream>

using namespace std;

class Complex{
    int real;
    int imag;
public:
    Complex(int r, int i): real(r), imag(i){}  //普通构造函数

    Complex(Complex& c){
        this->real = c.getReal();
        this->imag = c.getImag();
    }

    int getReal()const{
        return this->real;
    }

    int getImag()const{
        return this->imag;
    }
};

int main(){
    Complex* a = new Complex(3, 5);
    Complex* b = new Complex(*a); //调用拷贝构造函数,构造出指向新的Complex对象,值和a完全一样

    cout << "complex number a: " << a->getReal() << " + " << a->getImag() << "i" << endl;
    cout << "complex number a: " << b->getReal() << " + " << b->getImag() << "i" << endl;
}

同样地也可以采用重构赋值符号(operator=)的方式来直接复制一个对象:

#include<iostream>

using namespace std;

class Complex{
    int real;
    int imag;
public:
    Complex(int r, int i): real(r), imag(i){}  //普通构造函数

    Complex operator=(Complex& c){  //重构赋值操作符
        return Complex(c.getReal(), c.getImag());
    }

    int getReal()const{
        return this->real;
    }

    int getImag()const{
        return this->imag;
    }
};

int main(){
    Complex* a = new Complex(3, 5);
    Complex b = *a; //通过重构赋值操作符完成对象的拷贝

    cout << "complex number a: " << a->getReal() << " + " << a->getImag() << "i" << endl;
    cout << "complex number a: " << b.getReal() << " + " << b.getImag() << "i" << endl;
}

以上两种方式均可实现对一个拷贝一个对象的功能,除此之外C++还提供了一个新的方式叫做移动语义,也可以实现对象数据的复制。移动的关键词为std::move,其用法如下:

#include <iostream>

using namespace std;

int main()
{
    string text1 = "Hello, World!";
    string text2 = move(text1);
    cout << text2 << endl;
    return 0;
}

此时输出text2的结果如下:
在这里插入图片描述
那么问题来了,既然以上三种方式都能实现复制,那哪一种方法的性能最高呢?当然肯定是move的性能最高啦,否则要它干嘛呢。其实,复制赋值是基于L值实现的,而move则是基于R值实现的。
例如,有如下例子需要交换a和b:

int a = 5, int b = 3, temp;
temp = a;
a = b;
b = temp; //以上方式为复制交换

//以下方式为move交换
temp = move(a);
a = move(b);
b = move(temp);

以上代码的实现机理如下,左边为复制,右边为移动交换。
在这里插入图片描述
下面通过一个代码来测试一下二者的性能:

#include <iostream>
#include <chrono>

using namespace std;
using namespace chrono;

class Complex{
private:
    int re;
    int img;

public:
    Complex(int r, int i){
        this->re = r;
        this->img = i;
    }

    Complex operator=(const Complex& c){
        return Complex(c.getRe(), c.getRe());
    }

    int getRe()const{
        return this->re;
    }

    int getImg()const{
        return this->img;
    }
};

void swapViaCopy(Complex& a, Complex& b){
    Complex temp = a;
    a = b;
    b = temp;
}

void swapViaMove(Complex& a, Complex& b){
    Complex temp = move(a);
    a = move(b);
    b = move(temp);
}

int main()
{
    Complex a(2, 3);
    Complex b(3, 4); //定义2个复数
    Complex c(4, 5);
    Complex d(5, 6);
    auto start1 = system_clock::now(); //测量开始时的时间戳
    for(int i = 0; i < 10000; i++){
        swapViaCopy(a, b);
    }
    auto end1 = system_clock::now(); //测量结束时的时间戳
    cout << "swap via copy costs: " << nanoseconds(end1 - start1).count() << " ns" << endl;

    auto start2 = system_clock::now();
    for(int i = 0; i < 10000; i++){
        swapViaMove(c, d);
    }
    auto end2 = system_clock::now();
    cout << "swap via move costs: " << nanoseconds(end2 - start2).count() << " ns" << endl;
    return 0;
}

以上代码测试了对2个复数做一万次交换后的性能差达到了一个数量级。
在这里插入图片描述
因此用move实现的交换性能要高很多。

猜你喜欢

转载自blog.csdn.net/WJ_SHI/article/details/101411086