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

我已经阅读了下面的文章,这篇文章对移动语义有很好的理解:

但我仍然无法理解以下关于移动语义的事情-

  • 复制省略和RVO是否仍然适用于没有移动构造函数的类

  • 即使我们的类没有移动构造函数,但是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被设置为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;
    }