c++ - std::remove_if 移除的元素到哪里去了?

标签 c++ gcc stl

reference说是

template< class ForwardIt, class UnaryPredicate >
ForwardIt remove_if( ForwardIt first, ForwardIt last, UnaryPredicate p );

Iterators pointing to an elements between the old and the new ends of the range are still dereferenceable, but the elements themselves have unspecified values.

我尝试了这个简单的程序来找出“未指定的值”的含义。

#include <vector>
#include <memory>
#include <iostream>
#include <algorithm>

int main()
{
    std::vector< std::shared_ptr<int> > ints;
    for (int i = 0; i < 10; ++i)
        ints.push_back(std::make_shared<int>(i));
    std::remove_if(ints.begin(), ints.end(), 
                  [](const std::shared_ptr<int>& element)
                  {
                      return *element % 7 != 0;
                   });
    for (int i = 0; i < 10; ++i)
        std::cout << *ints[i] << std::endl;
    return 0;
}

输出是:

0
7
2
3
4
5
6
The program has unexpectedly finished.

那是第 7 个元素之后的数据发生了一些神秘的事情,这导致了段错误。

有趣的是,来自 here 的可能实现

template<class ForwardIt, class UnaryPredicate>
ForwardIt remove_if(ForwardIt first, ForwardIt last, 
                          UnaryPredicate p)
{
    ForwardIt result = first;
    for (; first != last; ++first) {
        if (!p(*first)) {
            *result++ = *first;
        }
    }
    return result;
}

不产生段错误。

这是一个错误吗?因为迭代器应该是可取消引用的。我正在使用 gcc 4.7.3

最佳答案

首先,以防万一您不知道,在使用 std::removestd::remove_if 时需要记住一些非常重要的事情:它们 实际上无法从底层容器中删除元素。这意味着他们自己实际上并没有移除任何东西。

您需要使用类似删除/删除 惯用法的东西:

auto to_erase = std::remove_if(ints.begin(), ints.end(), 
              [](const std::shared_ptr<int>& element)
              {
                  return *element % 7 != 0;
               });
ints.erase(to_erase, ints.end());

“删除”元素会发生什么是实现定义的。这是 gcc 实现:

  template<typename _ForwardIterator, typename _Predicate>
    _ForwardIterator
    remove_if(_ForwardIterator __first, _ForwardIterator __last,
          _Predicate __pred)
    {
      // concept requirements
      __glibcxx_function_requires(_Mutable_ForwardIteratorConcept<
                  _ForwardIterator>)
      __glibcxx_function_requires(_UnaryPredicateConcept<_Predicate,
        typename iterator_traits<_ForwardIterator>::value_type>)
      __glibcxx_requires_valid_range(__first, __last);

      __first = _GLIBCXX_STD_A::find_if(__first, __last, __pred);
      if(__first == __last)
        return __first;
      _ForwardIterator __result = __first;
      ++__first;
      for(; __first != __last; ++__first)
        if(!bool(__pred(*__first)))
          {
            *__result = _GLIBCXX_MOVE(*__first);
            ++__result;
          }
      return __result;
    }

可能导致段错误的原因是此实现调用了 _GLIBCXX_MOVE

关于c++ - std::remove_if 移除的元素到哪里去了?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16476308/

相关文章:

c++ - auto_ptr 内容的三元运算符不起作用

c++ - vector <unsigned char> 与二进制数据的字符串

c++ - 在 C++ 中使用十六进制字符串的按位函数 AND、OR 和 XOR

c++ - 为什么编译后没有.o?

C99 不是 GCC 的默认 C 版本?

batch-file - 安装 Win-builds 项目时如何在 yypkg 中为 sherpa.exe 设置代理信息

c++ - 标准::原子 | compare_exchange_weak 与 compare_exchange_strong

c# - 如何从 C++ 函数库调用 .Net COM+ 对象?

c++ - 导入错误 : No module named NetCDF

linux - 为 Linux 上的裸机 ARM 准备 GNU 工具链