Move semantics clarification
我读过下面的文章,它对移动语义有很好的理解:
Can someone please explain move semantics to me?
但是我仍然不理解下面关于移动语义的内容-
在没有移动构造函数的情况下,copy elision和rvo是否仍然适用于类?
即使我们的类没有move构造函数,但stl容器有一个。用于类似操作
std::vector vt=createMyclassVector();
为了执行诸如排序等操作,为什么STL不能在内部利用移动语义,使用不需要移动构造函数的复制省略或rvo之类的操作在内部改进这种操作?
三。在下面的案例中,我们是否受益于移动语义?-
std::vectorvt1(1000000,5);//创建并初始化100万个值为5的条目
std::vectorvt2(std::move(vt1));//将vt1移动到vt2
由于integer是一种基元类型,因此移动integer元素不会提供任何优势。或者,在移动操作之后,vt2只指向堆中的vt1内存,vt1设置为空。到底发生了什么?如果是后者,那么第2点也认为我们可能不需要为类移动构造函数。
4。当使用std::move on lvalue调用push_back()时,例如:
1 2 3 4 5 6 7 8 9 10
| 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如何通过简单地移动指向mem的指针来调整向量的连续内存需求?在堆的不同区域。
感谢您提前解释![按要求编辑问题。]
- 如果您使用指针,则不需要使用move。您可以只做.push_back(obj_ptr); obj_ptr = nullptr;移动语义是在处理对象本身时使用的。
- 感谢Bartek,我意识到并编辑了这个问题,尽管类MyClass可能有动态内存分配。
- 此外,逗号不用于句尾,请使用一些句号。
- 好的,然后再说一次:如果obj是一个pod,它就和你说的一样——它必须被复制。但是假设对象的唯一内容是指向缓冲区及其大小的指针。只有这两个可以通过move进行复制,而要执行完整复制,则必须复制缓冲区内容。
- 但是,指向缓冲区的指针是否会落在不同的内存地址上,仅仅移动它就不能满足向量所有元素的内存需求?
- 尼科尔:注意到了。
- 在被问到的问题中,只有第3点被解释为重复的问题(尽管这是一个很好的帖子)。我仍然不理解以下内容——a)move如何通过简单地移动指向堆不同区域内存的指针来调整向量连续内存需求。b)即使我们的类没有move构造函数,但是stl容器有一个。对于std::vectorvt=createMyclassVector()这样的操作,以及执行排序等操作,为什么stl不能在内部利用移动语义来改进此类操作?
大多数语义不是移动内存的方式。这一切都是关于对象所有权从一个对象实例转移到另一个对象实例。当你这样做的时候:
1 2
| std::string str1("Some string.");
std::string str2(std::move(str1)); |
std::string分配和管理字符缓冲区。因此,每个std::string都拥有一个内存缓冲区,其中包含字符串本身。
调用来构造str2的move构造函数将获取由str1分配的字符缓冲区,并将其从该对象中移除。因此,str2现在有了str1最初分配的指针,str1不再有该指针。这就是移动语义的全部意义:转移对象所拥有的内存的所有权。
如果您的类没有move构造函数,std::vector将不会调用它。很明显。因此,它不能利用移动构造函数可能带来的任何潜在优化。但是,这些优化机会只存在于具有值语义并且包含必须管理的资源的对象中。否则,运动对你没有帮助。
一般规则是使用智能指针和容器对象,如vector、string等,以避免编写移动构造函数。因此,(如果编译器正确地支持生成移动构造函数)资源管理将自动进行。
- 谢谢,是的,我的类没有move构造函数,但是stl容器有一个。所以说,当我将一个装满myclass对象的vector-vt复制到另一个vector-vt2中,或者执行排序等操作时,STL是否会在内部利用移动语义来改进这些操作?在最后一段中,您提到的一般经验法则是使用智能指针和STL容器,但是如果它们包含没有移动构造函数的用户定义类型,那么正如您提到的,它们可能不会受益,不是吗?.
- @悟空:不,因为你在复制矢量。向量将分配一个新的缓冲区,并将其每个对象复制到第二个向量中。如果向量是临时的(比如表达式的返回值,或者在v2 = std::move(v1)的情况下),那么stl将通过将整个缓冲区从v1移动到v2来进行杠杆作用,使v1为空。