在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实现的交换性能要高很多。