目录
对象移动
对象移动是 C++11 引入的核心特性,旨在通过转移资源所有权而非复制内容来提升性能。
移动构造函数
class Base {
public:
Base() : m_value(100) {
//std::cout << "类构造函数执行" << std::endl;
}
Base(const Base& other) : m_value(other.m_value) {}
virtual ~Base() {
//std::cout << "类的析构函数执行" << std::endl;
}
int m_value;
};
class BaseOwner {
public:
BaseOwner() : m_basePtr(new Base()) {
std::cout << "构造函数执行" << std::endl;
}
BaseOwner(const BaseOwner& other) : m_basePtr(new Base(*(other.m_basePtr))) {
std::cout << "类的拷贝构造函数" << std::endl;
}
//移动构造函数
BaseOwner(BaseOwner&& other)noexcept :m_basePtr(other.m_basePtr)
{
other.m_basePtr = nullptr;
std::cout << "移动构造函数" << std::endl;
}
virtual ~BaseOwner() {
delete m_basePtr;
std::cout << "析构函数执行" << std::endl;
}
private:
Base* m_basePtr;
};
noexcept是我们承诺一个函数不抛出异常的一种方法。我们在一个函数的参数列表后指定 noexcept。在一个构造函数中,noexcept出现在参数列表和初始化列表开始的冒号之间。一般情况下,移动构造函数都需要加
static BaseOwner get()
{
BaseOwner tmp;
return tmp;
}
int main()
{
//BaseOwner t = get();
BaseOwner t2 = (std::move(get()));
return 0;
}
这里使用std::move就会调用移动构造函数,而上一行代码在现版本的编译器优化下,已经不再调用拷贝构造函数。
而是直接将被返回的局部对象(tmp)构造到目标内存(t)中。
移动赋值运算符
下面我们为类BaseOwner增加拷贝赋值运算符和移动赋值运算符,参数上前者是左值引用后者是右值引用
BaseOwner& operator=(const BaseOwner& src)
{
if (this == &src)
return *this;
delete m_basePtr;
m_basePtr = new Base((*src.m_basePtr));
std::cout << "BaseOwner拷贝赋值运算符执行" << std::endl;
return *this;
}
BaseOwner& operator=(BaseOwner&& src)
{
if (this == &src)
return *this;
delete m_basePtr;
m_basePtr = src.m_basePtr;
src.m_basePtr = nullptr;
std::cout << "BaseOwner的移动赋值运算符执行" << std::endl;
return *this;
}
运行如下代码,我们将会调用移动赋值运算符
BaseOwner t3;
t3 = std::move(get());
合成的移动操作
当一个类没有定义任何自己版本的拷贝控制成员(包括拷贝构造函数、拷贝赋值运算符、移动构造函数、移动赋值运算符、析构函数),且类的每个非static数据成员都可以移动时,编译器才会为它合成移动构造函数或移动赋值运算符。编译器可以移动内置类型的成员。如果一个成员是类类型,且该类有对应的移动操作,编译器也能移动这个成员。