了解函数返回对象的移动语义

Understanding move semantics with objects returned by a function

本文关键字:移动 语义 对象 函数 返回 了解      更新时间:2023-10-16

我从 learncpp.com 遇到了以下程序,作为理解移动语义的示例。我尝试运行此程序,并按照教程中的说明查看程序流的工作方式。

但是,我在函数调用中无法理解它。

Auto_ptr4<Resource> generateResource()
{
Auto_ptr4<Resource> res(new Resource);
return res; // this return value will invoke the move constructor
}

据说将使用移动构造函数,但是当我设置断点并进行调试时,它根本没有这样做。

谁能帮助我理解为什么这里不调用移动构造函数?编译器会在这里省略吗?如果是这样,如何修改它以便它将调用移动构造函数。请解释一下这里发生了什么。

此外,如果您可以分享一些调用移动构造函数以及如何使用移动构造函数代替复制构造函数的示例,那就太好了。

#include <iostream>
template<class T>
class Auto_ptr4
{
T* m_ptr;
public:
Auto_ptr4(T* ptr = nullptr)
:m_ptr(ptr)
{
}
~Auto_ptr4()
{
delete m_ptr;
}
// Copy constructor
// Do deep copy of a.m_ptr to m_ptr
Auto_ptr4(const Auto_ptr4& a)
{
m_ptr = new T;
*m_ptr = *a.m_ptr;
}
// Move constructor
// Transfer ownership of a.m_mptr to m_ptr
Auto_ptr4(Auto_ptr4&& a)
: m_ptr(a.m_ptr)
{
a.m_ptr = nullptr;
}
// Copy assignment
// Do deep copy of a.m_ptr to m_ptr
Auto_ptr4& operator=(const Auto_ptr4& a)
{
// 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;
}
// Move assignment
// Transfer ownership of a.m_ptr to m_ptr
Auto_ptr4& operator=(Auto_ptr4&& a)
{
// Self-assignment detection
if (&a == this)
return *this;
// Release any resource we're holding
delete m_ptr;
// Transfer ownership of a.m_ptr to m_ptr
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; }
};
class Resource
{
public:
Resource() { std::cout << "Resource acquiredn"; }
~Resource() { std::cout << "Resource destroyedn"; }
};
Auto_ptr4<Resource> generateResource()
{
Auto_ptr4<Resource> res(new Resource);
return res; // this return value will invoke the move constructor
}
int main()
{
Auto_ptr4<Resource> mainres;
mainres = generateResource(); // this assignment will invoke the move assignment
return 0;
}

谢谢

Auto_ptr4<Resource> generateResource()
{
Auto_ptr4<Resource> res(new Resource);
return res; // this return value will invoke the move constructor
}

您的代码编写方式非常允许复制省略。C++标准有一整节专门讨论这个用例。

[class.copy.elision/1.1]

在具有类返回类型的函数的 return 语句中,当表达式是与函数返回类型相同类型(忽略 CV 限定)的非易失性自动对象(函数参数或处理程序的异常声明 ([except.handle])引入的变量除外)的名称时,可以通过将自动对象直接构造到函数调用的返回对象中来省略复制/移动操作

如果要防止省略,则需要返回一个不能合法省略的表达式。幸运的是,在这种情况下,强制调用移动构造函数也相当容易:

Auto_ptr4<Resource> generateResource()
{
Auto_ptr4<Resource> res(new Resource);
return std::move(res); // this return value will invoke the move constructor
}

由于现在表达式不是自动变量名,Auto_ptr4<Resource>&&也不完全相同Auto_ptr4<Resource>.c'tor 没有被省略。

这对于学习目的很好,但不要在实际代码中执行此操作。复制省略是一件非常好的事情,它可以提高代码的效率。让编译器在可能的情况下为您完成。