std::vector::assign-重新分配数据

std::vector::assign - reallocates the data?

本文关键字:分配 数据 新分配 vector assign- std      更新时间:2023-10-16

我正在使用STL库,我的目标是最大限度地减少数据重新分配的情况。说,我是在溺水

std::vector::assign(size_type n,const value_type&val)

如果大小没有改变,或者实际上只是分配了新值(例如,使用运算符=),则重新分配数据?

STL文档位于http://www.cplusplus.com/sais如下(C++98):

在填充版本(2)中,新内容是n个元素,每个元素初始化为val的副本。如果发生重新分配,则使用内部分配器来分配所需的存储。

调用之前保存在容器中的任何元素都将被销毁,并由新构建的元素替换(不会分配元素)。如果并且仅当新矢量大小超过当前矢量容量时,这会导致自动重新分配分配的存储空间。

"没有进行元素分配"这句话让这一切都有点令人困惑。

例如,我想要一个类的向量(例如,OpenCV的cv::Vec3i)。这是否意味着,

  1. 是否将调用cv::Vec3i的析构函数或构造函数
  2. Vec3i存储器的直接拷贝将被制作并填充矢量
  3. 如果我的类在运行时使用new分配内存,会发生什么情况操作人员普通内存无法解释此内存复制。这是否意味着,assign()不应该用于对象

编辑:在这种情况下使用assign的全部目的是将向量中的所有值设置为0(如果我有std::vector<cv::Vec3i>v)。它将被做很多次。std::vector本身的大小不会更改。

我想做的(用较短的方式)是:

 for(int i=0; i<v.size(); i++)  
   for(int j=0; j<3; j++)
     v[i][j] = 0;

现在我对C++98

感兴趣

std::vector.assign(...)在不必增长向量的情况下不会重新分配向量。不过,它必须复制实际元素。

如果你想知道标准保证了什么,可以看看标准:C++11标准加上小的编辑更改。

我假设您有一个填充了一些数据的向量,并对其调用赋值,这将:

  1. 像调用clear()一样销毁向量的所有元素(调用它们的析构函数)
  2. 用给定对象的n个副本填充现在为空的向量,该对象必须有一个副本构造函数

因此,如果你的类分配了一些内存,你必须:

  1. 在复制构造函数中处理这个问题
  2. 在析构函数中释放它

当大小超过分配的内存(矢量容量)时,会发生重新分配。您可以通过调用reserve()来防止这种情况发生。然而,我认为assign()足够聪明,可以在开始填充矢量之前和清除矢量之后分配所需的所有内存(如果这比已经分配的内存多)。

你可能想避免重新分配,因为它们的成本,但如果你试图避免它们,因为你的对象无法正确处理,那么我强烈建议你把它们放在向量中。

assign的语义以一种非常简单的方式定义为标准:

void assign(size_type n,const T&T);

效果:

erase(begin(), end());
insert(begin(), n, t);

这意味着首先将调用元素的析构函数。t的副本是在元素寿命结束后剩下的原始存储器中制作的。

要求value_typeMoveAssignable(当erase没有擦除到容器的末尾,并且需要将元素移向开头时)。

这里使用的insert过载要求value_typeCopyInsertableCopyAssignable.

在任何情况下,vector都不会注意到类是如何管理自己的资源的。这是你的责任。请参阅"三条规则"。

vector::resize方法的情况下,

std::vector::assign(size_type n, const value_type& val)

将每个元素初始化为"val"的副本。我更喜欢使用resize,因为它最大限度地减少了对象实例化/破坏的数量,但它也能做到这一点。如果您想最大限度地减少数据的重新分配,请使用resize,但请记住以下几点:

虽然这样做对某些数据结构是安全的,但要注意,分配/推送包含指向动态分配数据的指针的类的元素(例如,在构造函数中使用new)可能会造成严重破坏。

如果您的类动态分配数据,则应重新实现YourClass::operator=以将数据复制到新对象,而不是复制指针。

希望它能有所帮助!