C++ 如何编写无分支std::vector扫描?

C++ 如何编写无分支std::vector扫描?,c++,arrays,vector,conditional-statements,C++,Arrays,Vector,Conditional Statements,我想在数组上写一个简单的扫描。我有一个std::vector data,我想找到元素小于9的所有数组索引,并将它们添加到结果向量中。我可以用一个分支来写: for (int i = 0; i < data.size(); ++i) if (data[i] < 9) r.push_back(i); 使用数据的向量如何获得类似的行为?好吧,您可以事先调整向量大小并保留算法: // Resize the vector so you can index it nor

我想在数组上写一个简单的扫描。我有一个
std::vector data
,我想找到元素小于9的所有数组索引,并将它们添加到结果向量中。我可以用一个分支来写:

for (int i = 0; i < data.size(); ++i)
    if (data[i] < 9)
        r.push_back(i);

使用
数据的向量如何获得类似的行为?

好吧,您可以事先调整向量大小并保留算法:

// Resize the vector so you can index it normally
r.resize(length);

// Do your algorithm like before
int current_write_point = 0;
for (int i = 0; i < length; ++i){
    r[current_write_point] = i;
    current_write_point += (data[i] < 9);
}

// Afterwards, current_write_point can be used to shrink the vector, so
// there are no excess elements not written to
r.resize(current_write_point + 1);
让我们看看实际情况:

自动扫描分支(const std::vector&v)
{
std::向量res;
int insert_index=0;
对于(int i=0;i
这段代码的第26行显然有一个分支。如果大于或等于9,它只会继续下一个元素,但是如果小于9,则会执行一些可怕的代码来执行push_back,然后我们继续。没什么意外

auto scan_nobranch(const std::vector<int>& v)
{
  std::vector<int> res;
  res.resize(v.size());

  int insert_index = 0;
  for(int i = 0; i < v.size(); ++i)
  {
    res[insert_index] = i;
    insert_index += v[i] < 9;
  }

  res.resize(insert_index);
  return res;
}
自动扫描(const std::vector&v) { std::向量res; res.resize(v.size()); int insert_index=0; 对于(int i=0;i

然而,这一个只有一个条件移动,你可以在第190行中看到。看来我们赢了。由于条件移动不会导致管道暂停,因此在这一个中没有分支(除了for条件检查)。

data[i]<9
通常是程序集级别的分支(尽管与
push\u
相比,对于某些
cmov
魔术来说,它肯定是更好的候选,后者肯定不是)第二种解决方案如何以及为什么比第一种更好?我希望
current\u write\u point+=
行生成与
if(data[I]<9){current\u write\u point++}
@DimChtz相同的代码。我想这就是他试图找到的——他想比较这两种方法生成的代码。你分析过
std::partition()
然后是
std::copy()
在分割点?别忘了使用
current\u write\u point
来收缩
向量
之后。还有两个比较:
(data[i]<9)
i
@ThomasMatthews好吧,我只是给OP一种在算法中使用向量的方法,因为他/她想知道怎么做。据我所知,OP希望将这种代码与具有if@ThomasMatthews比较不是分支。@Nicolas,但就我所见,他的第二个代码片段不包含任何分支,因此他似乎意识到了这一点?甚至标题上也这么说……你能不能在答案中写下反汇编?谢谢:“RaKeE1111,当然,但是GooDeX颜色与C++代码和汇编代码的实际行匹配,在我看来,这更容易理解。你可以离开这个链接,但是如果将来某个时候链接死了,答案是不完整的:)你的编译器设置是什么?线圈展开了吗?
v.size()。。。第二个版本快了多少?虽然这段代码可能有助于解决问题,但它没有解释为什么和/或如何回答这个问题。提供这种额外的环境将大大提高其长期价值。请在回答中添加解释,包括适用的限制和假设。
#include <iostream>

// Use bitwise operations to determine if x is negative
int n(int x) {
    return x & (1 << 31);
}

int main() {
    int current_write_point = 0;
    for (int i = 0; i < length; ++i){
        r[current_write_point] = i;
        current_write_point += n(data[i] - 9);
    }
}
std::copy_if(std::begin(data), std::end(data), std::back_inserter(r));
auto scan_branch(const std::vector<int>& v)
{
  std::vector<int> res;
  int insert_index = 0;
  for(int i = 0; i < v.size(); ++i)
  {
    if (v[i] < 9)
    {
       res.push_back(i);
    } 
  }
  return res;
}
auto scan_nobranch(const std::vector<int>& v)
{
  std::vector<int> res;
  res.resize(v.size());

  int insert_index = 0;
  for(int i = 0; i < v.size(); ++i)
  {
    res[insert_index] = i;
    insert_index += v[i] < 9;
  }

  res.resize(insert_index);
  return res;
}