移动构造函数:是c++11新特性,进一步提高程序的效率
说明:
(1):A移动到B,那么A对象就不再使用了
(2):移动:并不是内存中的数据从一个地址到另外一个地址,而是知识所有的变更
拷贝构造函数:Time::Time(const Time &tem, int a = 30)
移动构造函数: Time::Time(const Time &&tem , int a =30)
移动构造函数和移动赋值运算符应该完成的功能:
(1) 完成必要的内存移动,斩断赋值运算符应该完成的功能
(2 ) 确保移动后原对象处于一种“即使被销毁也没有什么问题“的状态
#include <iostream>
using namespace std;
class B
{
public:
//默认构造函数
B() :m_bm(100)
{
//cout << "调用了B构造函数" << endl;
}
//拷贝构造函数
B(const B & tmp) :m_bm(tmp.m_bm)
{
//cout << "这里调用了B拷贝构造函数" << endl;
}
//析构函数
~B()
{
//cout << "这里调用了B析构函数" << endl;
}
int m_bm;
};
class A
{
public:
A() :m_pb(new B())
{
cout << "类A构造函数" << endl;
}
A(const A& tmps) :m_pb(new B( *(tmps.m_pb) )) //调用类B的拷贝构造函数
{
cout << "类A 的拷贝构造函数执行了" << endl;
}
//移动构造函数
//noexcept:通知标准库我们这个移动构造函数不抛出任何异常(提高编译器的工作效率)
A(A && tmpa) :m_pb(tmpa.m_pb) { //原来对象a指向的内存m_pb,直接就让这个临时对象指向这段内存。
tmpa.m_pb = nullptr;
cout << "类A的移动构造函数" << endl;
}
//拷贝赋值运算符
A& operator = (const A& src)
{
if (this == &src)
return *this;
else{
delete m_pb; //把自己的内存干掉
m_pb = new B(*(src.m_pb)); //重新分配一块内存
std::cout << "类A的拷贝赋值运算符被执行了" << endl;
return *this;
}
}
//移动赋值运算符
A& operator = (A && src)
{
if (this == &src)
return *this;
delete m_pb;//把自己的内存干掉;
m_pb = src.m_pb;//把对方的内存直接拿过来,直接指过来
src.m_pb = nullptr; //斩断源(也就是对方和那个内存相关的关联要斩断)
cout << "类A的移动赋值运算符被执行了" << endl;
return *this;
}
virtual ~A()
{
delete m_pb;
cout << "类A的析构函数被调用了" << endl;
}
private:
B *m_pb;
};
static A getA() //只能在本.cpp文件使用
{
A a;
return a; //临时对象
}
struct TC
{
int i; //内置类型可以移动
std::string s;//sting类型定义了自己的移动操作
};
int main()
{
//(1)
////移动构造函数演示
//B *bp = new B(); //new调用类B的构造函数
//bp->m_bm = 19;
//B *bp2 = new B(*bp); //这种给参数的new方法会调用B类的拷贝构造函数
//delete bp;
//delete bp2;
////(2)
//A a = getA();
////没有移动构造函数的时候:类A:调用了1次构造函数,1次拷贝构造函数,2次析构函数
////有移动构造函数的时候:调用了了一次构造函数,一次移动构造函数2次析构函数,从而整个程序的效率提高
////(3)
//A a = getA(); //1个构造函数,一个移动构造函数,一个析构函数
//A a2(a);//一个拷贝构造函数
////(4)
//A a = getA();
//A a2(std::move(a));//建立了新对象,调用新对象a2的移动构造函数
//A a3 = getA();
//A && a4(std::move(a3)); //这里没有建立新的对象,根本不会调用移动构造函数
// //效果等同于把对象,有了一个新的别名叫a4,后续建议用a4操作。
//A &&c = getA(); //从getA()返回的临时对象被c接管了。1个构造函数,一个移动构造函数,一个析构函数
////移动赋值运算符
////(4)
//A a = getA();
//A a2;
//a2 = std::move(a);//调用了移动赋值运算符
////(5)
////合成的移动操作
////某些条件下,编译器能合成移动构造函数,移动赋值运算符
////a)有自己的拷贝构造函数,自己的拷贝赋值运算符,或者自己的析构,那么编译器就不会为它合成移动构造函数和移动赋值运算符
// //b)如果我们没有自己的移动构造函数和移动赋值运算符,那么系统调我们自己写的拷贝构造函数和拷贝赋值运算符
////c)只有一个类没定义自己版本的拷贝构造成员(没有拷贝构造函数和拷贝运算符)。且类的每个非静态成员都可以移动时,编译器才会为该类合成移动构造函数或者移动赋值运算符
////什么叫做成员可以移动呢?
////(1)内置类型是可以移动的
////(2)类类型的成员,则这个类要有对应的移动操作相关的函数,就可以移动。
////此时编译器就能够为我们合成移动构造函数和移动赋值运算符
//TC a;
//a.i = 100;
//a.s = "I love China!";
//const char *p = a.s.c_str();
//
//TC b = std::move(a); //导致TC类的移动构造函数的执行,string类里的移动构造函数把s移动到b.s,而不是std::move()
//const char *q = b.s.c_str();
//总结
//(1) :尽量给类增加移动构造函数和移动赋值运算符
//(2) :noexcept
//(3) :该给nullptr 的要给,让被移动对象随时处于一种能够被析构的状态;
//(4):没有移动会调用拷贝替代。
system("pause");
return 0;
}