#include <iostream>
#include <cstring>
using namespace std;
class A {
public:
char *p;
A() {
p = new char[3];
};
A(const A& a) {
p = new char[3];
for(int i = 0; i < 3; ++i) {
p[i] = a.p[i];
}
}
// 移动构造
A(A&& a) {
cout << "in move constructor" << endl;
p = a.p;
a.p = nullptr;
}
// 移动赋值
A& operator=(A&& a) {
cout << "in move = operator" << endl;
p = a.p;
a.p = nullptr;
return *this;
}
~A() {};
};
int main()
{
/** 1. 对基础类型变量(如int)进行move操作,
move前后的变量(i, rr)指向了同一块内存空间;
如下例
(1) int &&rr = move(i); 之后i, rr对应同一块内存,值均为22;
(2) i = 44; 之后,i,rr的值均为44
*/
int i = 22;
int &&rr = move(i);
cout << "ori i = 22, move to rr" << endl;
cout << "i = " << i << endl; // 22
cout << "rr = " << rr << endl; // 22
cout << endl;
cout << "after i = 44" << endl;
i = 44;
cout << "i = " << i << endl; // 44
cout << "rr = " << rr << endl; // 44
cout << endl;
/** 2. 对含有指针的类进行move操作
(1) 为什么需要move
类中如果含有指针,那么对类对象在进行拷贝时,要思考进行深拷贝还是浅拷贝;
如果进行浅拷贝,对于类中的指针类型,只能copy指针的地址,并不能复制指针指向的内容;
如果进行深拷贝,对于类中的指针类型,则重新开辟了一块内存空间,copy指针指向的内容;
但是对于一些被copy之后不会再被用到的类对象,却还占据着空间,
于是希望引入"move",把原对象的内存"偷"过来,接管对原对象内存空间的管理权,
以达到节约开销,提高性能的目的;
(2) 如何move
对于类中的指针,在调用时一般是不可见的(如private类型的),
所以需要类的构造者在设计构造函数时,考虑如果将其进行拷贝or赋值操作时应如何处理指针。
对于move操作,有移动构造和移动赋值2种;
移动构造:在声明定义时进行初始化;见class A中的 A(A&& a)
移动赋值:用=赋值;见class A 中的 A& operator=(A&& a)
如果使用move,开发者要设计好类中的以上2中操作,一般是:
再创建一个新的指针,
用新指针地址 = 被复制对象的对应指针地址,
将被复制对象的对应指针 指向 设置为空。
*/
A a;
char *s = "ab";
a.p = s;
cout << "a.p = " << endl;
for(int i = 0; i < 3; ++i) {
// 这里转int可以看到字符串是否以 结束
cout << int(a.p[i]) << " "; // 97 98 0
}
cout << endl;
/////// 1. 普通的拷贝构造 //////////
A b(a);
cout << "b.p = " << endl;
for(int i = 0; i < 3; ++i) {
cout << b.p[i] << " "; // a b
}
cout << endl;
cout << endl;
/////// 2. 移动赋值 c = move(a); //////////
// 这里将 char* 强转 int* 为了获取指针p的地址
// 如果不强转, C++在对char*输出时,会默认输出指针所指向地址的值(ex."ab")
// 下例输出:
// in move = operator
// after A c = move(a)
// a.p = 0x0
// c.p = 0x10e3d0edb
A c;
c = move(a);
cout << "after A c = move(a)" << endl;
cout << "a.p = " << (int*)a.p << endl;
cout << "c.p = " << (int*)c.p << endl;
/////// 3. 移动构造 A e(move(d)); //////////
// in move constructor
// after e(move(d))
// d.p = 0x0
// e.p = 0x10e3d0f09
A d;
char *s2 = "cd";
d.p = s2;
A e(move(d));
cout << "after e(move(d))" << endl;
cout << "d.p = " << (int*)d.p << endl;
cout << "e.p = " << (int*)e.p << endl;
return 0;
}