【问题标题】:Move constructor never gets called [duplicate]移动构造函数永远不会被调用[重复]
【发布时间】:2018-09-30 12:04:32
【问题描述】:

我写了以下代码:

#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()

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

我期待以下输出:

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

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

【问题讨论】:

  • 允许(甚至要求)编译器在某些情况下省略复制和移动,即使构造函数或析构函数有副作用。最好发布您搜索的关键字。对此有很多答案。
  • 看起来编译器正在做一些优化。 -- 我希望如此。如果我使用的编译器生成了你说你希望看到的一个小小的 1 行程序的混乱,我会把它扔掉。
  • 如果要查看实际调用的移动构造函数,请使用std::move explicitly

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


【解决方案1】:

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

不,没有错。

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

这正是编译器所做的。

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

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

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


PS。

if (ptr) 在析构函数中是多余的。删除nullptr就好了。你也不要在operator= 进行检查,这很好。

deleteMe 是一个危险的函数。在一些非常晦涩的情况下,删除 self 可能很有用,但您的班级并没有显示出任何需要它。在非动态实例上调用此函数的行为将是未定义的。

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

【讨论】:

  • deleteMe 是为了尝试一些东西而写的。与此问题无关,因此将其从问题中删除以避免混淆。
猜你喜欢
  • 2013-08-31
  • 2012-10-10
  • 1970-01-01
  • 2013-03-13
  • 2018-08-08
  • 2016-07-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多