vector是否为std :: moved对象连续分配内存

时间:2020-05-26 05:16:20

标签: c++

如果我保留一定大小的向量,则我有一个循环,在该循环中,我取局部变量,然后取emplace_back(std::move(local_object)),因为std::move转移了内存的所有权。向量将具有连续位置的元素吗?

4 个答案:

答案 0 :(得分:3)

它移动local_object的内存内容,它不会神奇地移动内存本身。 vector有自己的存储空间,该存储空间始终是连续的。

答案 1 :(得分:2)

vector始终使用连续(连续)的存储位置。但是,如果std::move确实有帮助,那很可能是因为您的对象没有完全在本地存储自己的内存(某些数据存储在动态分配的内存中),并且非本地内存将保持非-本地(指向指针的指针作为移动构造的一部分移动,但它们指向的位置保持不变)。

简而言之,无法从move受益的部分将是连续的,而将从move受益的部分将保持原样。

答案 2 :(得分:2)

向量始终将元素存储在连续的位置。

添加新元素时,vector可能需要分配新内存并重新定位数据,以使元素适合连续位置。

reserve步骤进行一次内存分配,可以保证无需重新定位即可添加已保留空间的元素数量。

std::move不会移动任何东西。它在local_object上用于表示它可能被从移出,从而使move构造函数符合条件。是移动构造函数执行所有权的实际转移。

如果您的对象中有原始指针,则必须自己编写复制并移动构造函数(以及复制和移动赋值运算符)。参见the rule of 5

答案 3 :(得分:0)

这些不是语言规则,而是建筑概念:

  • 您必须记住,对象占用的存储空间不属于该对象。它由更高层次的东西拥有。这可以是另一个对象或过程,也可以是自动存储的功能。

  • 获得分配的动态内存的所有权假定可以控制新表达式返回的指针。一旦获得它,它就被“删除”了,直到由该值的持有者控制并停止存在。否则会“丢失”,导致所谓的内存泄漏。但是,最好考虑使用术语“资源所有权”来废止实施细节,并指定特定实体可以访问所述资源并控制其“生命”。

要分析表达式emplace_back(std::move(local_object)),应该考虑到这一点

  1. Vector不拥有存储对象的资源。它需要用于存储对象的资源所有者。

  2. 如果类型T的存储对象拥有一些资源,则它们不会将所有权传递给容器。他们继续拥有他们。

  3. 如果有可用空间,
  4. emplace_backvector拥有的内存位置中构造一个类型T的 new 对象。否则,它将重新分配vector的存储空间以获取所需的资源。 emplace_back的参数用作类型T的构造函数的参数。

  5. std::move不会移动任何东西。它是 xvalue表达式的标准助记符,等效于将表达式结果用作 rvalue引用类型的参数的表达式强制转换。

  6. 由于emplace_back的参数是对类型T的原始对象的右值引用,因此调用了“移动构造函数”。如果用户为类型T定义了构造函数,那么在向量完成分配后 由用户负责。

  7. 如果也没有为T定义用户定义的移动和复制构造函数以及赋值运算符,则也没有用户定义的析构函数,则编译器会隐式声明move构造函数。隐式声明的move构造函数遵循声明的所有成员的定义语义:

    • 对于所有类类型的子对象,将调用移动构造函数,如果适用,则从基类子对象开始。
    • 对于所有基本类型和数组,将复制其存储内容。
  8. 如果T包含不可移动的T的任何非静态成员,不可移动的直接或虚拟基类,或者T是类联合的类并且具有具有用户定义的move构造函数的成员。

  9. 移动能力意味着在当前上下文中可以访问明确且未删除的move构造函数。

因此,emplace_back会导致所有权从T类型的原始对象转移到新建的对象,只有在用户为T类型的对象或其任何子对象定义了移动构造函数的情况下对象和整个集团是可移动的。如果不满足该要求,则将考虑通过复制构造函数的调用来构造新对象。否则,它不过是浅表副本。