std :: remove_if GCC实现效率不高?

时间:2014-02-13 23:00:28

标签: c++ gcc

another question here开始,似乎有证据表明,与以下实施相比,海湾合作委员会对std::remove_if的实施并不能提供同等效率:

'raw homebrew' solution

static char str1[100] = "str,, ing";
size_t size = sizeof(str1)/sizeof(str1[0]);

int bad = 0;
int cur = 0;
while (str1[cur] != '\0') {
    if (bad < cur && !ispunct(str1[cur]) && !isspace(str1[cur])) {
        str1[bad] = str1[cur];
    }
    if (ispunct(str1[cur]) || isspace(str1[cur])) {
        cur++;
    } else {
        cur++;
        bad++;
    }
}
str1[bad] = '\0';

时间输出:

  

0.106860

Sample benchmarking code std::remove_if代表同一问题的解决方案:

bool is_char_category_in_question(const char& c) {
    return std::ispunct(c) || std::isspace(c);
}

std::remove_if(&str1[0], &str1[size-1], is_char_category_in_question);

时间输出:

  

1.986838

检查并获取运行上述ideone链接的代码的实际运行时结果(在此处给出完整代码会模糊问题!)。

鉴于提供的执行时间结果(来自样本),这些似乎证实了第一个实现具有更好的性能。

任何人都可以说出原因,为什么std::remove_if()算法没有(或不能)为给定问题提供类似有效的解决方案?

3 个答案:

答案 0 :(得分:5)

对我来说,好像你在remove_if为100的情况下在100个字符的范围内运行size,但“自制软件”一直运行,直到找到nul终结符(只有10个字符)在)。

使用下面评论中的更改来处理,在带-O2的GCC上,我仍然看到差异大约为2,而remove_if更慢。改为:

struct is_char_category_in_question {
    bool operator()(const char& c) const {
        return std::ispunct(c) || std::isspace(c);
    }
};

几乎消除了所有这些差异,尽管可能仍然存在<10%的差异。所以这看起来像是一个实施质量问题,无论测试是否内联,尽管我没有检查程序集确认。

由于您的测试工具意味着在第一次通过后没有实际删除任何字符,因此我不会感到10%的差异。我有点惊讶,但还不足以真正进入它。 YMMV: - )

答案 1 :(得分:1)

您可以尝试使用擦除删除习惯用于小改进。

std::string str{str1};
for(i=0;i<999999L;++i) {
    str.erase( std::remove_if(std::begin(str), std::end(str), is_char_category_in_question), std::end(str) );
}

这与Steve Jessop提到的其他问题相结合,因此我将size - 1替换为10,但如果您愿意,可以使用strlen。对于此测试,我的Makefile看起来像:

compile:
    g++ test.cpp -o test -std=c++11 -O3
    g++ test2.cpp -o test2 -std=c++11 -O3
    g++ test3.cpp -o test3 -std=c++11 -O3
run:
    perf stat -r 10 ./test
    perf stat -r 10 ./test2
    perf stat -r 10 ./test3

test是删除删除版本,test2remove_if版本,test3是其他版本。结果如下:

 Performance counter stats for './test' (10 runs):

       0.035699861 seconds time elapsed                                          ( +-  2.30% )

perf stat -r 10 ./test2

 Performance counter stats for './test2' (10 runs):

       0.050991938 seconds time elapsed                                          ( +-  2.96% )

perf stat -r 10 ./test3

 Performance counter stats for './test3' (10 runs):

       0.038070704 seconds time elapsed                                          ( +-  2.34% )

我省略了详细信息,我只运行了10次。您可以自己尝试测试,以便更好地解释结果。

答案 2 :(得分:0)

你的改进了remove_if!一段时间以来一直在为压缩比赛而战,而你的伎俩只能将速度提高3点。 我添加了一些我的技巧(如嵌入迭代器的函数对象),如下所示:

从vector v:

中删除even size_t
class RemoveEven {
public :
  RemoveEven (std::vector<size_t>::iterator& i) : i_ (i) {}
  ~RemoveEven () {}
  void operator () (size_t& s) {
    if (s%2) *i_++ = s;
  }
private :
  std::vector<size_t>::iterator& i_;
};

int main (int argc, char* argv []) {
  size_t tmp [5] = {1, 2, 4, 5, 7};
  size_t* p ((size_t*) tmp);
  std::vector<size_t> v (p, p+5);
  std::cout << "v init :";
  for (std::vector<size_t>::const_iterator i (v.begin ()); i != v.end (); ++i) std::cout << *i << " ";
  std::cout << std::endl;

  std::vector<size_t>::iterator i (v.begin ());
  std::for_each (v.begin (), v.end (), RemoveEven (i));
  if (i != v.end ()) v.erase (i, v.end ());
  std::cout << "v odd :";
  for (std::vector<size_t>::const_iterator i (v.begin ()); i != v.end (); ++i) std::cout << *i << " ";
  std::cout << std::endl;
}

正常输出:

v init :1 2 4 5 7 
v odd :1 5 7