c++11学习笔记(4)- 移动构造函数与移动语义

文章目录

    • @[toc]
  • 1.移动构造函数
  • 2. std::move

1.移动构造函数

什么是移动构造函数呢?
我们首先来看一个例子:

#include 
#include 

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(Object&& object)

使用移动构造函数 Object(Object&& object) 将临时对象的堆内存转移到对象o2中,并使用代码object.m_pMem = nullptr; 以便object临时对象能够安全的被析构。
Object&& 实际上上一个 右值引用 ,关于右值引用可以参考上一篇文章
左值、右值和右值引用

在C++中这样“偷走”临时变量中资源的构造函数,就叫做 移动构造函数 ;而这样“偷”的行为就叫做 移动语义。移动语义在资源共享时,可以起到关键的作用。

2. std::move

在c++11中,标准库在 中提供了一个有用的函数 std::move,这个函数并不移动任何东西,他唯一的功能是将一个左值强制转化为右值引用,以用于移动语义

值得一提的是,被转化的左值,其生命周期并没有随着左右值得转化而改变。

我们将上面的代码改写一下:

#include 
#include 

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是不可移动的确是可拷贝的,那么拷贝语义将会用于这个置换。


作者:douzhq
个人主页:https://www.douzhq.cn
文章同步页:https://douzhq.cn/c11_4/

你可能感兴趣的:(C++,c++11,移动构造,std::move)