我读过下面的文章,它对移动语义学有很好的见解:
有人能给我解释一下语义学吗?
但是我仍然不明白关于移动语义学的以下事情-
>
复制省略和RVO是否仍然适用于没有移动构造函数的类?
即使我们的类没有移动构造函数,但STL容器有一个。对于像
std::向量
为什么STL不能在内部利用移动语义学,在内部使用不需要移动构造函数的复制省略或RVO等操作来改进此类操作?
3.在以下情况下,我们是否受益于移动语义学-
std::向量
std::向量
因为整数是一个基本类型,移动整数元素不会提供任何优势。或者在这里,在移动操作之后,vt2简单地指向堆中的vt1内存,vt1设置为null。实际发生了什么?如果后者是这种情况,那么即使是第2点也认为我们可能不需要为我们的类移动构造函数。
4.当使用st调用push_back()时d::移动左值,例如:
std::vector<MyClass> vt;
for(int i=0; i<10; ++i)
{
vt.push_back(MyClass());
}
MyClass obj;
vt.push_back(std::move(obj));
现在,由于向量具有连续内存分配,并且obj被定义在内存中的其他位置,如何移动语义学将obj内存移动到向量vt连续内存区域,在这种情况下移动内存不会像复制内存一样好,移动如何通过简单地移动指向堆不同区域内存的指针来证明向量连续内存的要求?
感谢提前解释!
[最初发布为移动语义学澄清,但现在随着上下文的变化,将其发布为新问题,应删除旧问题ASAP。]
复制省略和RVO是否仍然适用于没有移动构造函数的类?
是的,RVO仍然生效。实际上,编译器应该选择:
为什么STL不能在内部利用移动语义学在内部使用不需要移动构造函数的复制省略或RVO等操作来改进此类操作?
STL容器是可移动的,无论其中存储的类型如何。但是,对容器中对象的操作需要对象协作,因此,排序(例如)只能在对象可移动时移动对象。
在下面的情况下,我们是否受益于移动语义学[…]因为整数是原始类型?
是的,你知道,因为容器是可移动的,不管它们的内容如何。正如你推断的,st2
会从st1
中窃取内存。不过,移动后st1
的状态是未指定的,所以我不能保证它的存储空间会被取消。
当push_back()
调用时,使用std::左值移动
[会发生什么]?
调用左值类型的移动构造函数,通常这涉及将原始内容按位复制到目标中,然后将原始内容作废。
一般来说,移动构造函数的成本与sizeof(object)
成正比;例如,sizeof(std::string)
是稳定的,无论std::string
有多少个字符,因为实际上这些字符存储在堆上(至少当它们的数量足够时),因此只有指向堆存储的指针被移动(加上一些元数据)。
std::向量
有一个移动构造函数,可以避免复制所有元素。例如。
struct MyClass
{
MyClass(MyClass&& other)
: xs(other.xs), size(other.size)
{
other.xs = nullptr;
}
MyClass(const MyClass& other)
: xs(new int[other.size]), size(other.size)
{
memcpy(xs, other.xs, size);
}
~MyClass()
{
delete[] xs;
}
int* xs;
int size;
}
使用移动构造函数,只有xs
和size
需要复制到向量中(用于连续内存),但是我们不需要像复制构造函数那样执行内存分配和memcpy
。