繁体   English   中英

std :: move和对象的构造/销毁

[英]std::move and construction/destruction of objects

我记得,在调用任何函数之前,它会在堆栈中为函数结果和参数分配内存。 这是否意味着我有

T func()
{
    T a;
    return std::move(a);
}

我仍将进行复制,因为已经为整个T分配了内存? 我也读过类似的问题

return a; 

与...相同

return std::move(a);

所以,我无法避免复制到堆栈? rvalue是堆栈中的值吗?

这是在某个地方使用它的好方法吗?

T a = std::move(func());

所以我会避免复制函数的结果? 我仍然需要创建特殊的move构造函数和move operator =吗?

我试图对其进行测试并得到:

class Temp
{
public:
    Temp()
    {
        cout << "construct" << endl;
        i = 5;
    }
    ~Temp()
    {
        cout << "destruct" << endl;
    }
    Temp(const Temp& t)
    {
        i = t.i;
        cout << "copy construct" << endl;
    }
    Temp operator=(const Temp& t)
    {
        i = t.i;
        cout << "operator =" << endl;
        return *this;
    }
    int i;

};

Temp tempfunc1()
{
    Temp t1;
    t1.i = 7;
    return t1;
}

Temp tempfunc2()
{
    Temp t1;
    t1.i = 8;
    return std::move(t1);
}

int main()
{
        Temp t1;
        Temp t2;
        t2.i = 6;
        t1 = t2;
        cout << t1.i << endl;
        t1.i = 5;
        t1 = std::move(t2);
        cout << t1.i << endl;
        cout << "NEXT" << endl;
        t1 = tempfunc1();
        cout << t1.i << endl;
        cout << "NEXT" << endl;
        t1 = std::move(tempfunc1());
        cout << t1.i << endl;
        cout << "NEXT" << endl;
        t1 = tempfunc2();
        cout << t1.i << endl;
        cout << "NEXT" << endl;
        t1 = std::move(tempfunc2());
        cout << t1.i << endl;
}

结果:

construct
construct
operator =
copy construct
destruct
6
operator =
copy construct
destruct
6
NEXT
construct
copy construct
destruct
operator =
copy construct
destruct
destruct
7
NEXT
construct
copy construct
destruct
operator =
copy construct
destruct
destruct
7
NEXT
construct
copy construct
destruct
operator =
copy construct
destruct
destruct
8
NEXT
construct
copy construct
destruct
operator =
copy construct
destruct
destruct
8

好像使用std :: move没有任何作用。 还是在存在特定构造函数和析构函数的情况下有效?

为什么“ t1 = t2”同时调用复制构造函数和operator =?

抱歉,我问了这么多问题,这些问题可能非常简单,即使在阅读了很多有关此问题之后,也许是因为我的英语不好,我仍然需要解释。

先感谢您。

我对您的代码进行了一些更改,这些更改可能有助于您理解和探索所有工作原理。 我向每个Temp对象添加了一个id元素,以使其更容易理解哪个对象,并且还更改了operator=的签名以返回引用而不是对象。 首先,这是使其成为完整程序所需的include

#include <iostream>
using std::cout;
using std::endl;

接下来,这是现在包含std::move构造函数(带有&& )和move =运算符的类:

class Temp
{
    int id;
public:
    Temp() : id(++serial), i(5)
    {
        cout << "construct " << id << endl;
    }
    ~Temp()
    {
        cout << "destruct " << id << endl;
    }
    Temp(const Temp& t) : id(++serial), i(t.i)
    {
        cout << "copy construct " << id << " from " << t.id << endl;
    }
    Temp(Temp &&t) : id(++serial), i(t.i)
    {
        t.i = 5;  // set source to a default state
        cout << "move construct " << id << " from " << t.id << endl;
    }
    Temp &operator=(const Temp& t)
    {
        i = t.i;
        cout << "operator = " << id << " from " << t.id << endl;
        return *this;
    }
    Temp &operator=(Temp&& t)
    {
        i = t.i;
        t.i = 5;  // set source to a default state
        cout << "move operator = " << id << " from " << t.id << endl;
        return *this;
    }
    int i;
    static int serial;
};


int Temp::serial = 0;

您的功能仍然相同,但请参阅注释

Temp tempfunc1()
{
    Temp t1;
    t1.i = 7;
    return t1;
}

Temp tempfunc2()
{
    Temp t1;
    t1.i = 8;
    return std::move(t1);   // not necessary to call std::move here
}

我对main()进行了些微改动,以显示其全部工作原理:

int main()
{
    Temp t1;   
    Temp t2;   
    t2.i = 6;   
    t1 = t2;   
    cout << t1.i << endl;
    t1.i = 5;
    t1 = t2;
    cout << t1.i << endl;
    cout << "NEXT" << endl;
    t1 = tempfunc1();
    cout << t1.i << endl;
    cout << "NEXT" << endl;
    t1 = std::move(tempfunc1());
    cout << t1.i << endl;
    cout << "NEXT" << endl;
    t1 = tempfunc2();
    cout << t1.i << endl;
    cout << "NEXT" << endl;
    Temp t3(tempfunc1());
    cout << t3.i << endl;
    cout << "NEXT" << endl;
    Temp t4(t1);
    cout << t4.i << endl;
}

最后是输出:

construct 1
construct 2
operator = 1 from 2
6
operator = 1 from 2
6
NEXT
construct 3
move operator = 1 from 3
destruct 3
7
NEXT
construct 4
move operator = 1 from 4
destruct 4
7
NEXT
construct 5
move construct 6 from 5
destruct 5
move operator = 1 from 6
destruct 6
8
NEXT
construct 7
7
NEXT
copy construct 8 from 1
8
destruct 8
destruct 7
destruct 2
destruct 1

如您所见,使用fixed operator= ,不会创建任何临时文件。 同样,一旦提供了operator=的移动版本,临时对象(与tempfunc1()tempfunc2()函数返回的对象一样)将自动使用移动语义。 您的tempfunc2()实际上并不需要std::move调用。 如您所见,这只会产生另一个临时性,因此带来的伤害大于帮助。 最后请注意,在创建t3 ,只创建了一个对象,不需要临时或move构造函数。

更新

值得注意的是,在这个琐碎的类中,move构造函数实际上并没有多大帮助,但是对于使用分配的内存或创建计算量很大的类,它可以提供很多帮助。 在这种情况下,记住移动构造函数(或在operator=的移动版本中)需要多个步骤是很有用的。 具体来说,您必须:

  1. 释放目标对象使用的所有资源,然后
  2. 将资源从源对象移动到目标对象,然后
  3. 设置源对象状态,以便可以调用析构函数(例如,如果类已分配了内存,则应将指针设置为nullptr以便析构函数可以正确运行),最后,
  4. 返回*this

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM