我已经阅读了以下帖子,它非常了解移动语义:
但是我仍然无法理解关于移动语义的一些事情 -
复制elision和RVO是否仍适用于没有移动构造函数的类?
即使我们的类没有移动构造函数,但STL容器也有。适用于
std::vector<MyClass> vt = CreateMyClassVector();
并执行排序等操作。为什么STL内部不能使用移动语义来在内部使用不需要移动构造函数的copy elision或RVO等操作来改进这些操作?
3。 在下面的情况下,我们是否会受到移动语义的影响 -
std::vector< int > vt1(1000000, 5); // Create and initialize 1 million entries with value 5
std::vector< int > vt2(std::move(vt1)); // move vt1 to vt2
由于整数是基本类型,移动整数元素不会提供任何优势。 或者在移动操作之后,vt2只指向堆中的vt1内存,并且vt1设置为null。究竟发生了什么?如果是后一种情况,那么即使是第2点也认为我们的类可能不需要移动构造函数。
4。 当使用std :: move on lvalue调用push_back()时,例如:
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连续的内存区域,在这种情况下移动内存不会像复制内存一样好,如何通过简单地移动指向堆的不同区域中的内存的指针来移动证明向量连续的内存需求。
感谢提前解释!
[最初发布为Move semantics clarification但现在随着上下文的更改,将其作为新问题发布,应尽快删除旧问题。]
答案 0 :(得分:2)
复制elision和RVO是否仍适用于没有移动构造函数的类?
是的,RVO仍在继续。实际上,编译器应该选择:
为什么STL内部不能利用移动语义在内部使用不需要移动构造函数的copy elision或RVO等操作来改进此类操作?
无论存储在哪个类型中,STL容器都是可移动的。但是,对 in 容器中的对象的操作需要对象协作,因此 sort (例如)只有在这些对象可移动时才能移动对象。
在下面的情况下,我们是否会受到移动语义的影响[...],因为整数是一种原始类型?
是的,你这样做,因为容器 可移动,无论其内容如何。如您所推断,st2
将从st1
窃取内存。移动后st1
的状态未指定,因此我无法保证其存储空间无效。
在左值上使用
push_back()
调用std::move
时[会发生什么]?
调用左值类型的移动构造函数,通常这涉及将原始的按位副本复制到目标中,然后对原始文件进行无效化。
通常,移动构造函数的成本与sizeof(object)
成比例;例如,sizeof(std::string)
是稳定的,无论std::string
有多少个字符,因为实际上这些字符存储在堆上(至少当它们有足够数量时),因此只有<移动堆存储的em>指针(加上一些元数据)。
答案 1 :(得分:1)
std::vector
有一个移动构造函数,可以避免复制所有元素。e.g。
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
复制构造函数。