c++ - 了解函数返回的对象的 move 语义

标签 c++ constructor move-semantics

我从 learncpp.com 看到以下程序作为理解 move 语义的示例。我试着运行这个程序,看看程序流程是如何按照教程中的解释工作的。

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

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

据说会使用 move 构造函数,但当我设置断点和调试时它根本没有这样做。

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

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

#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 acquired\n"; }
    ~Resource() { std::cout << "Resource destroyed\n"; }
};

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]

in a return statement in a function with a class return type, when the expression is the name of a non-volatile automatic object (other than a function parameter or a variable introduced by the exception-declaration of a handler ([except.handle])) with the same type (ignoring cv-qualification) as the function return type, the copy/move operation can be omitted by constructing the automatic object directly into the function call's return object

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

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 没有被省略。

这对于学习目的来说很好,但不要在实际代码中这样做。复制省略是一件非常好的事情,可以提高代码的效率。让编译器尽可能为您完成。

关于c++ - 了解函数返回的对象的 move 语义,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44922222/

相关文章:

c++ - 为什么 struct 设计要扩展导致它很像类?

c++ - 如何在 C++ 类中创建私有(private)动态数组?

c++ - constructor\destructor 或者对OOP的理解

c++ - ref-qualifier `const &&` 有什么用?

c++我可以用double初始化一个float类型的变量吗?

c++ - nCk 模 p 当 n % p 或 k % p == 0

JAVA使用构造函数创建每个类的两个具有完整数据的对象,但出现错误

java - 为什么我不能在 Java 中扩展具有不明确构造函数的类?

c++ - C++14如何提高 "str1 + str2 + str3 + ..."的效率?

c++ - 如果 std::move 会导致意外复制,则强制编译时错误?