【问题标题】:Most efficient way to split a vector into several将向量拆分为多个的最有效方法
【发布时间】:2014-08-27 06:58:00
【问题描述】:

我有以下代码将 vectorOfInterest 分解成更小的块以发送出去。 此代码正在运行。

但是,当我将 vectorOfInterest 拆分为更小的块时(在 subList 和剩余部分的构造函数中),我会进行复制。 有没有更好的使用移动而不是再次复制数据以获得更好的性能?

请注意,我无法更改 OTHERCLASS::doSend() 的参数

编辑:我使用的是 C++98

int blockSize = 50;
vector <CLASS_T> vectorOfInterest; 

// ...<populates vectorOfInterest>
do {
    if(vectorOfInterest.size()> blockSize)
        vector<CLASS_T>iterator from = vectorOfInterest.begin();
        vector<CLASS_T>iterator to = from + blockSize;

        //elements are copied again in subList and remainder
        //I like to move the elements from vectorOfInterest instead.
        vector<CLASS_T> subList (from, to);  
        vector<CLASS_T> remainder (to, vectorOfInterest.end());
        vectorOfInterest.swap(remainder);

        OTHERCLASS::doSend (subList); // method which sends sublists in blocks of exactly 50 to external library
    }else {
        //pad to exactly size 50 
        vectorOfInterest.resize(blockSize);

         OTHERCLASS::dosend (vectorOfInterest); // method which sends sublists in blocks of exactly 50 to external library

        vectorOfInterest.clear();
    }

while ( !vectorOfInterest.empty());

【问题讨论】:

  • 有一些方法可以提高效率,但我能想到的都需要你更改OTHERCLASS::doSend()(例如,保留boost::shared_ptr&lt;CLASS_T&gt; 的向量,以便复制shared_ptrs不复制CLASS_Ts;将一对迭代器传递给OTHERCLASS::doSend(),这样它就无法访问原始元素而不是它们的副本。
  • 也许这篇stackoverflow.com/questions/4707012/c-memcpy-vs-stdcopy 的帖子也有帮助。在某些平台上 memcpy 可能更快......但我会选择你的实现

标签: c++ vector c++98


【解决方案1】:

您不应该在每次迭代时都从 vectorOfInterest 中删除元素。这涉及大量不必要的复制。相反,保持一个持久的迭代器。您还可以避免每次迭代都分配子列表。

vector<CLASS_T>::iterator from = vectorOfInterest.begin();
vector<CLASS_T> subList;

do {
    if(vectorOfInterest.end() - from > blockSize) {    
        subList.assign(from, from + blockSize);
        from += blockSize;    
        OTHERCLASS::doSend(subList);
    }else {            
        subList.assign(from, vectorOfInterest.end());
        subList.resize(blockSize);    
        OTHERCLASS::dosend (subList);    
        vectorOfInterest.clear();
        subList.clear();
    }    
} while ( !vectorOfInterest.empty());

【讨论】:

    【解决方案2】:

    如果您不需要真实副本并且原始向量保持不变且可访问,则可以将适当的迭代器范围 boost::iterator_range&lt;std::vector&lt;CLASS_T&gt;::iterator&gt; 发送到库。对于这种方法,我假设其他类采用行为类似于容器的模板参数。

    【讨论】:

    • "请注意,我无法更改 OTHERCLASS::doSend() 的参数"
    • @BenjaminLindley 谢谢你的评论。我在答案中添加了我对doSend() 的假设。
    【解决方案3】:

    更重要的优化可能是在创建剩余部分时完成的过度复制。

    试试这个:

    int blockSize = 50;
    vector <CLASS_T> vectorOfInterest; 
    vector <CLASS_T> subList(blockSize);
    
    size_t vectorSize = vectorOfInterest.size();
    
    for(int i = 0; i < vectorSize(); i += blockSize)
    {
        vector<CLASS_T>iterator from = vectorOfInterest.begin() + i;
        size_t thisBlockSize = min(i+blockSize, vectorSize);
        vector<CLASS_T>iterator to = vectorOfInterest.begin() + thisBlockSize;
    
        //replace this with an elementwise swap if you can
        std::copy(from, to, subList.begin());
        std::fill(to, vectorOfInterest.end(), /*what ever you want*/);
    
        OTHERCLASS::doSend (subList);
    }
    

    编辑:我刚刚看到了 C++98 部分。搬家是没有问题的。换句话说,您在循环中分配了两次新向量,并将每个元素复制了两次。通过在循环上方预分配一个向量,您只分配了一个向量(doSend 收到的那个)。避免复制元素两次更难。由于您可以使向量的元素无效,因此可以交换然后复制。

    【讨论】:

      猜你喜欢
      • 2017-04-01
      • 2019-09-17
      • 2019-04-20
      • 2012-04-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多