Move Contsructor & rvalue References
Problem of Temporary Objects
这篇文章的主要目的是研究如何使用move语义去降低内存中临时对象的负载。每次从函数中返回一个对象时,都会有一个临时对象被创建出来,然后进行拷贝。最终我们将会创建出两个对象,但实质上我们只需要一个。
举个例子,我们有一个容器类:
1 | class Container { |
这个类中,我们每次创建一个容器对象,其默认构造器都会分配一个20个int大的数组在堆上。同理,容器类的靠背构造器也会做类似的工作,首先是分配数组,然后将传递进的数组内容拷贝到新创建出数组里。
一般来说,我们使用工厂类来创建对象:
1 | Container getContainer() |
假设我们创建一个容器类型的vector,每次插入一个由getContainer()返回的对象:
1 | int main() { |
vector里的一个对象,实际上背后我们为此创建了两个对象。
- 一个是在getContainer()使用Container类的默认函数创建出来的;
- 一个是在加入vector中使用Container类的拷贝构造函数创建出来的;
这样每一个对象,都会带来两次在heap上创建数组。
Solving Problem of Temporary Objects using rvalue references & Move Constructor
getContainer()函数实际上是一个右值,所以可以被右值引用指向。因此为了实现这个目的,我们可以重载一个新的构造器,即move构造器:
Move Constructor
Move构造函数将右值引用作为参数,并重载该函数。在move构造函数中,我们只是将传递对象的成员变量move到新对象的成员变量中,而不是分配新内存。
1 | Container(Container && obj) |
在移动构造函数中,我们只是复制了指针,即成员变量m_Data指向了堆上的相同内存,然后将传递进的对象的m_Data设置为NULL。所以我们并没有在该构造函数中分配新的内存,而是转移了内存的控制。
现在再将getContainer()返回的对象push到数组中,由于getContainer()是一个右值,因此会调用container类的move构造器,此时只会创建一个整数数组。