移动构造函数永远不会被调用

时间:2018-09-30 12:04:33

标签: c++ c++11 compiler-optimization move-constructor

我写了下面的代码:

#define LOG cout << __PRETTY_FUNCTION__ << endl;

class MyClass
{
private:
    int* ptr;

public:
    MyClass()
        : ptr(new int(10))
    {
        LOG
    }

    ~MyClass()
    {
        LOG

        if (ptr)
        {
            delete ptr;
            ptr = nullptr;
        }
    }

    MyClass(const MyClass& a)
        : ptr(nullptr)
    {
        LOG
        ptr = new int;
        *ptr = *(a.ptr);
    }

    MyClass& operator=(const MyClass& a)
    {
        LOG
        if (this == &a)
        {
            return *this;
        }

        delete ptr;
        ptr = new int;
        *ptr = *(a.ptr);

        return *this;
    }

    MyClass(MyClass&& a)
        : ptr(nullptr)
    {
        LOG

        ptr = a.ptr;
        a.ptr = nullptr;
    }

    MyClass& operator=(MyClass&& a)
    {
        LOG

        if (this == &a)
        {
            return *this;
        }

        delete ptr;
        ptr = a.ptr;
        a.ptr = nullptr;

        return *this;
    }

    void printClass()
    {
        LOG;
    }
};

MyClass function()
{
    MyClass m;
    return m;
}

int main()
{
    MyClass m = function();
    return 0;
}

程序输出:

MyClass::MyClass()
MyClass::~MyClass()

这不会调用move构造函数。有什么问题吗?

我期待以下输出:

MyClass::MyClass()
MyClass::MyClass(MyClass&&)
MyClass::~MyClass()
MyClass::MyClass(MyClass&&)
MyClass::~MyClass()
MyClass::~MyClass()

看起来编译器正在做一些优化。如果是这种情况,那为什么我们需要移动构造函数或移动赋值运算符。

1 个答案:

答案 0 :(得分:2)

  

这不会调用move构造函数。有什么问题吗?

不,没有错。

  

看起来编译器正在做一些优化。

这正是编译器所做的。

  

如果是这种情况,那么为什么我们需要为该情况移动构造函数或赋值运算符。

您的类需要自定义的move构造函数和赋值运算符,因为隐式生成的类将无法正确处理分配的资源。

仅仅因为编译器可能乐观,并不是将它们排除在外的好理由。尤其是因为在其他程序中,根本无法优化移动。


PS。

析构函数中的

if (ptr)是多余的。删除nullptr很好。您也不必在operator=中进行检查,这很好。

deleteMe是危险功能。在一些非常晦涩的情况下,删除自我可能很有用,但是您的班级对此没有任何要求。在非动态实例上调用此函数的行为是不确定的。

在移动复制副本构造函数中将ptr初始化为null是多余的,因为您无条件地在构造函数的主体中覆盖了该值。