可以乱序插入向量吗?

Posted

技术标签:

【中文标题】可以乱序插入向量吗?【英文标题】:Can insert into vector Out of order? 【发布时间】:2021-04-21 08:37:09 【问题描述】:

我想通过vec2vec3 插入vec1。当我先插入vec3时,程序无法成功退出。但是当我插入vec2再插入vec3时,程序可以成功退出。 我想知道失败的原因。

为什么插入vec1 乱序:我想通过两个不同的线程插入(两个线程会写入不同的位置,互不影响),所以顺序不能得到保证。

#include <iostream>
#include <vector>
#include <chrono>

using namespace std::chrono;
using namespace std;


struct DocIdAndPayLoad


    uint64_t m_docId;

    DocIdAndPayLoad()
    
        DefaultCnt++;
    


    DocIdAndPayLoad(const DocIdAndPayLoad& /*_bond_rhs*/)
    
        CopyCnt++;
    


    DocIdAndPayLoad(DocIdAndPayLoad&& _bond_rhs)
    
        MoveCnt++;
    


    DocIdAndPayLoad& operator=(const DocIdAndPayLoad& _bond_rhs)
    
        AssignCnt++;
        return *this;
    


    static int DefaultCnt;
    static int CopyCnt;
    static int MoveCnt;
    static int AssignCnt;
;

int DocIdAndPayLoad::DefaultCnt = 0;
int DocIdAndPayLoad::CopyCnt = 0;
int DocIdAndPayLoad::MoveCnt = 0;
int DocIdAndPayLoad::AssignCnt = 0;

int main()

    const int hugeSize=10000;
    vector<DocIdAndPayLoad> vec1;
    cout<<vec1.size()<<" "<<vec1.capacity()<<endl;

    vector<DocIdAndPayLoad> vec2(hugeSize/2);
    vector<DocIdAndPayLoad> vec3(hugeSize/2);

    auto start1 = high_resolution_clock::now();
    vec1.reserve(hugeSize);
    
    //vec1.insert(vec1.begin()+hugeSize/2, std::make_move_iterator(vec3.begin()), std::make_move_iterator(vec3.end()));
    vec1.insert(vec1.begin(), std::make_move_iterator(vec2.begin()), std::make_move_iterator(vec2.end()));
    
    auto stop1 = high_resolution_clock::now();
    auto duration = duration_cast<microseconds>(stop1 - start1);
    cout << "Cost1: "<< duration.count() << " microseconds" << endl;

    vector<DocIdAndPayLoad> vec4;
    auto start2 = high_resolution_clock::now();
    vec4.resize(hugeSize);
    auto stop2 = high_resolution_clock::now();
    auto duration2 = duration_cast<microseconds>(stop2 - start2);
    cout << "Cost2: "<< duration2.count() << " microseconds" << endl;

    cout<<vec1.size()<<" "<<vec1.capacity()<<endl;
         
    return 0;



【问题讨论】:

当两个线程插入同一个向量时,你需要某种同步 两个线程会写入两个不同的位置,互不影响。 好吧,这不是 insert 的作用。在向量中插入元素可能会导致重新分配。如果您预先调整大小然后访问单独的元素,那很好。顺便说一句,我不明白您发布的代码有什么问题。那就是崩溃的代码? 我认为reverseresize 更有效,因为reverse 不调用构造函数。我想访问std::vector::reverse分配的原始内存,怎么办? 【参考方案1】:

reserve 调用设置向量的容量,但不设置其大小。这意味着调用后向量仍然是空的

vec1.reserve(hugeSize);

该向量中的任何索引都将超出范围并导致未定义的行为。

更重要的是,由于向量是空的,vec1.begin() 将返回 end 迭代器(即vec1.begin() == vec1.end()),所以vec1.begin()+hugeSize/2 无效!

尝试取消引用 end 迭代器(或更多)会导致未定义的行为和可能的崩溃。

【讨论】:

谢谢。您是否有我提到的问题的解决方案(通过两个不同的线程插入)?我不能使用 resize,因为 DocIdAndPayLoad 的构造函数成本太高了。 @Alfred 为什么不让每个线程在自己的向量上工作,并在所有线程完成后按要求的顺序插入最终向量 (vec1)? insert in the required order 使其顺序,这应该是并行的,因为插入成本太高。 如何写入reserve分配的原始内存? @Alfred 也许您需要以实际数组的形式使用“原始内存”,然后如果您想要一个类似容器的对象,请使用该数组的视图?还是使用不同的容器?您是否尝试过例如双端队列或列表或其他自定义容器?

以上是关于可以乱序插入向量吗?的主要内容,如果未能解决你的问题,请参考以下文章

C++ 向量和列表插入

乱序插入导致索引膨胀

排序算法视频版 | 直接插入排序

插入排序

使用迭代器和向量的插入排序实现

排序算法插入排序