C++ C++;11移动语义行为特定问题
我已经阅读了下面的文章,这篇文章对移动语义有很好的理解: 但我仍然无法理解以下关于移动语义的事情-C++ C++;11移动语义行为特定问题,c++,c++11,move-semantics,rvalue-reference,C++,C++11,Move Semantics,Rvalue Reference,我已经阅读了下面的文章,这篇文章对移动语义有很好的理解: 但我仍然无法理解以下关于移动语义的事情- 复制省略和RVO是否仍然适用于没有移动构造函数的类 即使我们的类没有移动构造函数,但是STL容器有一个。对于像这样的操作 std::vector vt=CreateMyClassVector() 以及执行排序等操作。为什么STL不能在内部利用移动语义,使用不需要移动构造函数的复制省略或RVO等操作来改进这些操作 三,。 在下面的例子中,我们是否从移动语义中获益- std::vectorvt1(1
std::vector vt=CreateMyClassVector()代码>
以及执行排序等操作。为什么STL不能在内部利用移动语义,使用不需要移动构造函数的复制省略或RVO等操作来改进这些操作
三,。
在下面的例子中,我们是否从移动语义中获益-
std::vectorvt1(1000000,5);//创建并初始化100万个值为5的条目
std::vectorvt2(std::move(vt1));//将vt1移动到vt2
由于integer是一种基本类型,移动integer元素不会带来任何好处。
或者在这里,在移动操作之后,vt2只是指向堆中的vt1内存,vt1被设置为null。到底发生了什么?如果是后者,那么即使第2点也认为我们的类可能不需要移动构造函数
四,。
使用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));
std::vector vt;
对于(int i=0;i
对
他们尽可能做到这一点
是。std::vector
有一个移动构造函数,可以避免复制所有元素
它仍然在附近
e、 g
对于移动构造函数,只需将xs
和size
复制到向量中(对于连续内存),但是我们不需要像复制构造函数那样执行内存分配和memcpy
复制省略和RVO是否仍然适用于没有移动构造函数的类
是的,RVO仍然有效。实际上,编译器应该选择:
- RVO(如有可能)
- 移动施工(如果可能)
- 复制构造(最后手段)
为什么STL不能在内部利用移动语义,使用不需要移动构造函数的复制省略或RVO等操作在内部改进此类操作
STL容器是可移动的,与其中存储的类型无关。但是,对容器中对象的操作需要对象协作,因此,排序(例如)只能在对象可移动的情况下移动对象
在下面的例子[…]中,我们是否受益于移动语义,因为integer是一种基本类型
是的,您可以这样做,因为容器是可移动的,无论其内容如何。正如您推断的,st2
将从st1
窃取内存。但是移动后st1
的状态未指定,因此我无法保证其存储将被取消
使用左值上的std::move
调用push_back()
时[发生了什么]
调用左值类型的move构造函数,这通常涉及将原始值按位复制到目标中,然后对原始值进行null化
通常,移动构造函数的成本与sizeof(object)
成正比;例如,sizeof(std::string)
是稳定的,无论std::string
有多少个字符,因为实际上这些字符都存储在堆上(至少在有足够数量的字符时)因此,只有指向堆存储的指针被移动(加上一些元数据)。谢谢@ronag:标准是否提到了第2点。我还没有真正理解你对第3点的评论,是的,vector确实有移动构造函数,但这里它做了成员移动(这相当于复制整数的情况)对于所有元素或简单地使向量vt2指向向量v1的堆分配。对于没有为向量元素分配内存的点4,您如何将xs复制到它,如果您只是复制指针,那么它将指向不在向量连续内存2中的内存区域。STl使用RVO和类似优化,方式与任何其他优化相同代码.3.它不执行成员移动,其工作原理与MyClass示例类似。4.仅MyClass(即,它的成员X和大小)需要在内存中保持连续,MyClass是否有指向其他地方的指针无关紧要。谢谢,您提到的容器是可移动的向量st2将从st1窃取内存,您的意思是st2现在将指向st1对象内存布局(就像RVO一样)并且不需要移动st1的每个整数成员。那么,在字符串对象的后一种情况下,为什么它只需要将大小和指针复制到缓冲区,而可以直接指向字符串对象的对象内存布局,并将原始对象设置为空值,这有点像RVO的工作方式。它只是创建了一个对临时对象的新引用。@Goku:1/Vector:yes,the指向日期/大小/容量的指针以某种方式从st1
传输到st2
。2/String:同样的情况发生,指向日期/大小/容量的指针从一个字符串传输到另一个字符串。
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;
}