什么是移动构造函数呢?
我们首先来看一个例子:
#include <iostream>
#include <stdlib.h>
class Object
{
public:
Object() {
std::cout << "Object()" << std::endl;
m_pMem = new char[10];
memset(m_pMem, 0, 10);
}
~Object(){
delete m_pMem;
}
Object(const Object& object) {
std::cout << "Object(const Object&)" << std::endl;
m_pMem = new char[10];
memcpy(m_pMem, object.m_pMem, 10);
}
Object getObject(void) {
Object obj;
return obj;
}
private:
char* m_pMem = nullptr;
};
int main(int argc, char** argv)
{
Object o1;
Object o2 = o1.getObject();
system("pause");
}
该示例的运行结果为:
Object()
Object()
Object(const Object&)
代码main()函数中 Object o1; 执行了一次普通构造函数;函数 getObject 也执行了一次普通构造函数并生成一个临时的 Object 对象,这里由于编译器的优化,这个临时对象就是函数中的 obj 本身; o2 对象的创建执行了一次拷贝构造函数。
如果我们能够把函数 getObject 产生的临时对象直接赋值给 o2 那该有多好啊,这样就可以不用使用拷贝构造再重新生成内存了,提升了程序的效率。那么有没有什么办法实现呢,当然是有的,使用移动构造函数,我们在上面的类 Object 中添加如下代码:
Object(Object&& object) {
std::cout << "Object(Object&& object)" << std::endl;
m_pMem = object.m_pMem;
object.m_pMem = nullptr;
}
使用移动构造函数 Object(Object&& object) 将临时对象的堆内存转移到对象o2中,并使用代码object.m_pMem = nullptr; 以便object临时对象能够安全的被析构。
Object&& 实际上上一个 右值引用 ,关于右值引用可以参考上一篇文章
左值、右值和右值引用
在c++11中,标准库在
我们将上面的代码改写一下:
#include <iostream>
#include <stdlib.h>
class Object
{
public:
Object() {
std::cout << "Object()" << std::endl;
m_pMem = new char[10];
memset(m_pMem, 0, 10);
}
~Object(){
delete m_pMem;
}
Object(const Object& object) {
std::cout << "Object(const Object&)" << std::endl;
m_pMem = new char[10];
memcpy(m_pMem, object.m_pMem, 10);
m_Number = object.m_Number;
}
Object(Object&& object) {
std::cout << "Object(Object&& object)" << std::endl;
m_pMem = object.m_pMem;
object.m_pMem = nullptr;
m_Number = object.m_Number;
}
Object getObject(void) {
Object obj;
return obj;
}
int m_Number = 10;
private:
char* m_pMem = nullptr;
};
int main(int argc, char** argv)
{
Object o1;
Object o2 = std::move(o1);
std::cout << o1.m_Number << std::endl;
system("pause");
}
运行结果为
Object()
Object(Object&& object)
10
可见 o1 并没有因为左右值得转换而被释放。
有了移动语义,我们可以实现一个高效率的置换(swap)函数,代码如下:
template<typename T>
void swap(T& t1, T& t2)
{
T temp(std::move(t1));
t1 = std::move(t2);
t2 = std::move(temp);
}
如果T是可移动的,那么移动构造和移动赋值将用于这个替换,提高交换的效率;如果T是不可移动的确是可拷贝的,那么拷贝语义将会用于这个置换。