我正在尝试使用以下代码理解移动语义。
以下是输出结果。
如您所见,
#include <iostream>
#include <utility>
using namespace std;
class A
{
public:
int a;
A():a{1}{}
A(A&& rref):a{rref.a}{cout<<"move constructor called"<<endl;}
A(const A& ref):a{ref.a}{cout<<"copy constructor"<<endl;}
};
int main(){
A original; // original object
cout<<"original.a = "<<original.a<< "| address original.a="<< &(original.a)<<endl;
A movedto (std::move(original)); // calls A(A&&)
cout<<"original.a = "<<original.a<< "| address original.a"<< &(original.a)<<endl;
cout<<"movedto.a = "<<movedto.a<<"| address movedto.a"<< &(movedto.a)<<endl;
return 0;
}
以下是输出结果。
original.a = 1| address original.a=0x7fff1611b6d0
move constructor called
original.a = 1| address original.a0x7fff1611b6d0
movedto.a = 1| address movedto.a0x7fff1611b6e0
如您所见,
original.a
和movedto.a
的地址不同,因此成员变量a
在A(A&& rref):a{rref.a}
中进行了复制操作。
我知道对于内置类型,移动操作会退化为复制操作。我的问题是,如果我想劫持(而非复制)类的实例该怎么办?假设我有100个内置类型的成员变量(而非只有一个),那么复制的代价就很大了。
一种明显的方法是将对象存储在堆上,并使用引用语义来传递它。但我想保持值语义,并仍然能够规避复制。
std::vector<int>
成员并移动它。它会为您处理一切。 - Bo Perssonstd::vector<T>
是否具有值语义?2)如果问题1的答案是肯定的,那么vector<T>
会做什么? - Howard Hinnanta{rref.a}
应该改为a{std::move(rref.a)}
以实际移动a
(尽管对于int
来说仍然会复制,因为它是相同的)。 - NathanOlivera
定义为什么类型,original.a
和movedto.a
仍然具有不同的地址。 - Benjamin Lindleyrref.a
是一个lvalue,因为rref
是一个lvalue(命名的右值引用)。如果你想让它成为xvalue,你需要std::move(rref.a)
。或者,如果你做了std::move(rref).a
,那么它也可以工作,因为这样。
运算符将从一个rvalue提供一个rvalue。 - wally