C++11 引入了对象移动而非拷贝的概念,移动并不是把内存中的数据从一个地址挪到另外一个地址,仅仅是所有者的变更。有时候对象发生拷贝后就被销毁了,这种情况下移动而非拷贝对象会大幅度提升性能。
移动构造函数和移动赋值运算符应该完成的功能:完成必要的内存移动,斩断原对象和内存的关系,确保移动后原对象处于一种“即使被销毁也没有什么问题”的状态,确保移动后不再使用原对象。
#include
using namespace std;
class B
{
private:
int m_data;
public:
B(int x = 0) : m_data(x) {}
B(const B& tmpb) : m_data(tmpb.m_data) {}
virtual ~B() {}
};
class A
{
private:
B* m_pb;
public:
A() : m_pb(new B()) // 这里会调用类B的构造函数
{
cout << "类A的构造函数执行了 - " << this << endl;
}
A(const A& tmpa) : m_pb(new B(*(tmpa.m_pb))) // 这里会调用类B的拷贝构造函数
{
cout << "类A的拷贝构造函数执行了 - " << this << endl;
}
virtual ~A()
{
delete m_pb;
cout << "类A的析构函数执行了 - " << this << endl;
}
};
static A fun()
{
A a;
return a;
}
int main()
{
fun();
cout << "--------------------------------" << endl;
A a1 = fun();
cout << "--------------------------------" << endl;
A a2(a1);
cout << "--------------------------------" << endl;
A a3(std::move(a1));
cout << "--------------------------------" << endl;
return 0;
}
输出结果如下:
#include
using namespace std;
class B
{
private:
int m_data;
public:
B(int x = 0) : m_data(x) {}
B(const B& tmpb) : m_data(tmpb.m_data) {}
virtual ~B() {}
};
class A
{
private:
B* m_pb;
public:
A() : m_pb(new B()) // 这里会调用类B的构造函数
{
cout << "类A的构造函数执行了 - " << this << endl;
}
A(const A& tmpa) : m_pb(new B(*(tmpa.m_pb))) // 这里会调用类B的拷贝构造函数
{
cout << "类A的拷贝构造函数执行了 - " << this << endl;
}
// noexcept:通知标准库这个移动构造函数不抛出任何异常,提高编译器工作效率
A(A&& tmpa) noexcept : m_pb(tmpa.m_pb)
{
tmpa.m_pb = nullptr;
cout << "类A的移动构造函数执行了 - " << this << endl;
}
virtual ~A()
{
delete m_pb;
cout << "类A的析构函数执行了 - " << this << endl;
}
};
static A fun()
{
A a;
return a; // 如果类A有移动构造函数,那么会调用移动构造函数把a对象的数据移动给临时对象
}
int main()
{
fun();
cout << "--------------------------------" << endl;
A a1 = fun();
cout << "--------------------------------" << endl;
A a2(a1);
cout << "--------------------------------" << endl;
A a3(std::move(a1));
cout << "--------------------------------" << endl;
return 0;
}
输出结果如下:
#include
using namespace std;
class B
{
private:
int m_data;
public:
B(int x = 0) : m_data(x) {}
B(const B& tmpb) : m_data(tmpb.m_data) {}
virtual ~B() {}
};
class A
{
private:
B* m_pb;
public:
A() : m_pb(new B()) // 这里会调用类B的构造函数
{
cout << "类A的构造函数执行了 - " << this << endl;
}
A(const A& tmpa) : m_pb(new B(*(tmpa.m_pb))) // 这里会调用类B的拷贝构造函数
{
cout << "类A的拷贝构造函数执行了 - " << this << endl;
}
// noexcept:通知标准库这个移动构造函数不抛出任何异常,提高编译器工作效率
A(A&& tmpa) noexcept : m_pb(tmpa.m_pb)
{
tmpa.m_pb = nullptr;
cout << "类A的移动构造函数执行了 - " << this << endl;
}
A& operator=(const A& src)
{
if (this == &src) return *this;
delete m_pb;
m_pb = new B(*(src.m_pb));
cout << "类A的拷贝赋值运算符执行了 - " << this << endl;
return *this;
}
virtual ~A()
{
delete m_pb;
cout << "类A的析构函数执行了 - " << this << endl;
}
};
static A fun()
{
A a;
return a;
}
int main()
{
A a1;
cout << "--------------------------------" << endl;
a1 = fun();
cout << "--------------------------------" << endl;
A a2;
cout << "--------------------------------" << endl;
a2 = std::move(a1);
cout << "--------------------------------" << endl;
return 0;
}
输出结果如下:
#include
using namespace std;
class B
{
private:
int m_data;
public:
B(int x = 0) : m_data(x) {}
B(const B& tmpb) : m_data(tmpb.m_data) {}
virtual ~B() {}
};
class A
{
private:
B* m_pb;
public:
A() : m_pb(new B()) // 这里会调用类B的构造函数
{
cout << "类A的构造函数执行了 - " << this << endl;
}
A(const A& tmpa) : m_pb(new B(*(tmpa.m_pb))) // 这里会调用类B的拷贝构造函数
{
cout << "类A的拷贝构造函数执行了 - " << this << endl;
}
// noexcept:通知标准库这个移动构造函数不抛出任何异常,提高编译器工作效率
A(A&& tmpa) noexcept : m_pb(tmpa.m_pb)
{
tmpa.m_pb = nullptr;
cout << "类A的移动构造函数执行了 - " << this << endl;
}
A& operator=(const A& src)
{
if (this == &src) return *this;
delete m_pb;
m_pb = new B(*(src.m_pb));
cout << "类A的拷贝赋值运算符执行了 - " << this << endl;
return *this;
}
A& operator=(A&& src) noexcept
{
if (this == &src) return *this;
delete m_pb;
m_pb = src.m_pb;
src.m_pb = nullptr;
cout << "类A的移动赋值运算符执行了 - " << this << endl;
return *this;
}
virtual ~A()
{
delete m_pb;
cout << "类A的析构函数执行了 - " << this << endl;
}
};
static A fun()
{
A a;
return a;
}
int main()
{
A a1;
cout << "--------------------------------" << endl;
a1 = fun();
cout << "--------------------------------" << endl;
A a2;
cout << "--------------------------------" << endl;
a2 = std::move(a1);
cout << "--------------------------------" << endl;
return 0;
}
输出结果如下:
如果一个类定义了自己的拷贝构造函数、拷贝赋值运算符或析构函数,编译器就不会为它合成移动构造函数和移动赋值运算符。
如果我们没有自己的移动构造函数和移动赋值运算符,那么系统会调用我们自己写的拷贝构造函数和拷贝赋值运算符来代替。
当一个类没有定义任何自己版本的拷贝构造函数、拷贝赋值运算符、析构函数,且类的每个非静态数据成员都可以移动时,编译器才会为它合成移动构造函数或移动赋值运算符。