我记得,在任何函数调用之前,它会为堆栈中的函数结果和参数分配内存。 这是否意味着我有
T func()
{
T a;
return std::move(a);
}
我仍然会复制,因为已经为整个T分配了内存? 我也读过类似的问题
return a;
与
相同return std::move(a);
那么,我无法避免复制到堆栈? rvalue是否为堆栈值?
在某处使用它是否是好方法:
T a = std::move(func());
所以我会避免复制功能的结果?我是否还需要创建特殊的移动构造函数并移动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 =?
请原谅我可能非常简单的大量问题,即使在阅读了很多相关内容之后,也许是因为我的英语不好,我仍然需要解释。
提前谢谢。
答案 0 :(得分:3)
我对您的代码进行了一些更改,这可能有助于您了解和探索这一切是如何运作的。我在每个id
对象中添加了一个Temp
元素,以便更容易理解哪个对象是哪个,并且还更改了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
如您所见,使用固定的operator=
,不会创建临时值。此外,一旦提供了operator=
的移动版本,临时对象(与您的tempfunc1()
和tempfunc2()
函数返回的对象一样)会自动使用移动语义。您的tempfunc2()
确实不需要std::move
内的t3
电话。正如你所看到的那样,这仅仅创造了另一种临时性,所以它的伤害超过了它的帮助。最后请注意,在创建move
时,只创建了一个对象,并且不需要临时或operator=
构造函数。
可能值得注意的是,移动构造函数在这个简单的类中并没有多大帮助,但它对于使用已分配内存或计算成本昂贵的类有很大帮助。在这些情况下,记住移动构造函数(或nullptr
的移动版本)中需要多个步骤是有用的。具体来说,您必须:
*this
,以便析构函数将正常运行),然后最后,< / LI>