通过一个例子来说明移动构造和普通构造函数的区别。这个例子也是参考网上的文章做的,原文忘记了。
测试环境:Ubuntu 16.04 LTS
如果一个class动态分配了内存,则普通构造和移动构造有以下区别:
普通构造:会进行深拷贝,涉及到构造和析构
移动构造:不会进行深拷贝,直接对对象的所有权进行转移,效率更高。
下面的示例代码,在generateResource return时,会进行一次拷贝。
如果注释掉移动构造版本的代码,则运行时调用普通的构造函数,log如下:
Auto_ptr3()::=
Resource acquired
Resource ===
~Auto_ptr3()
Resource destroyed
如果打开移动构造版本的代码,则运行时调用移动构造函数,log如下:
Auto_ptr3()::=,move
~Auto_ptr3()
由此可见,如果一个class动态分配了内存,移动构造的效率更高。
/*
copy constructor
copy assignment
拷贝数据。
move copy constructor
move copy assignment
转移所有权。
*/
#include <iostream>
template<class T>
class Auto_ptr3
{
T* m_ptr;
public:
Auto_ptr3(T* ptr = nullptr)
:m_ptr(ptr)
{
std::cout << "Auto_ptr3()" << std::endl;
}
~Auto_ptr3()
{
std::cout << "~Auto_ptr3()" << std::endl;
delete m_ptr;
}
// Copy constructor
// Do deep copy of a.m_ptr to m_ptr
Auto_ptr3(const Auto_ptr3& a)
{
std::cout << "Auto_ptr3()::copy" << std::endl;
m_ptr = new T;
*m_ptr = *a.m_ptr;
}
// Copy assignment
// Do deep copy of a.m_ptr to m_ptr
Auto_ptr3& operator=(const Auto_ptr3& a)
{
std::cout << "Auto_ptr3()::=" << std::endl;
// Self-assignment detection
if (&a == this)
return *this;
// Release any resource we're holding
delete m_ptr;
// Copy the resource
m_ptr = new T;
*m_ptr = *a.m_ptr;
return *this;
}
#if 1
// Copy constructor
// move
Auto_ptr3(Auto_ptr3&& a):m_ptr(a.m_ptr)
{
std::cout << "Auto_ptr3()::copy,move" << std::endl;
a.m_ptr = nullptr;
}
// Copy assignment
// move
Auto_ptr3& operator=(Auto_ptr3&& a)
{
std::cout << "Auto_ptr3()::=,move" << std::endl;
// Self-assignment detection
if (&a == this)
return *this;
// Release any resource we're holding
delete m_ptr;
// move the ownership
m_ptr = a.m_ptr;
a.m_ptr = nullptr;
return *this;
}
T& operator*() const { return *m_ptr; }
T* operator->() const { return m_ptr; }
bool isNull() const { return m_ptr == nullptr; }
#endif
};
class Resource
{
public:
Resource() { std::cout << "Resource acquired\n"; }
~Resource() { std::cout << "Resource destroyed\n"; }
Resource& operator=(const Resource& a){ std::cout << "Resource ===\n"; }
private:
int m_a;
};
Auto_ptr3<Resource> generateResource()
{
/*
1.new Resource:"Resource acquired"
2.res(new Resource),执行Auto_ptr3的构造函数:"Auto_ptr3()"
3.打印“222222222222222”
4.执行Auto_ptr3的assignment constructor,
"Auto_ptr3()::=",
"Resource acquired\n",
"Resource ===\n"
5.res析构,~Auto_ptr3()
Resource destroyed
*/
Auto_ptr3<Resource> res(new Resource);
std::cout << "222222222222222\n\n";
return res;
}
int main()
{
Auto_ptr3<Resource> mainres; // 执行Auto_ptr3的构造函数:"Auto_ptr3()"
std::cout << "111111111111111\n";
mainres = generateResource(); // this assignment will invoke the copy assignment
/* 实际测试发现,函数返回的时候,没有执行copy constructor,而是直接执行的assignment constructor */
std::cout << "\n3333333333333333\n";
return 0;
}
/*
使用copy constructor和assignment constructor的版本
Auto_ptr3()
111111111111111
Resource acquired
Auto_ptr3()
222222222222222
Auto_ptr3()::=
Resource acquired
Resource ===
~Auto_ptr3()
Resource destroyed
3333333333333333
~Auto_ptr3()
Resource destroyed
使用move的版本
Auto_ptr3()
111111111111111
Resource acquired
Auto_ptr3()
222222222222222
Auto_ptr3()::=,move
~Auto_ptr3()
3333333333333333
~Auto_ptr3()
Resource destroyed
*/