c++ - 是否允许标准库算法复制谓词参数?

标签 c++ g++ functor stl-algorithm

假设我们想从 int vector 中删除重复值。通常的解决方案是使用 erase-remove 习惯用法对 vector 进行排序并删除重复项。但是我们需要维护不会被移除的元素的顺序,所以我们无法排序。所以有人可能想出这样的谓词并使用 with with remove_if 算法:

struct comp {
    std::set<int> s;
    comp() : s() {}
    bool operator()(int i)
    {
        return !(s.insert(i)).second;
    }
};

但是如果谓词对象由于某种原因被复制,这将中断,因为我们将获得 set 成员的两个拷贝。事实上,gcc 的 remove_if 实现正是这样做的:

template<typename _ForwardIterator, typename _Predicate>
    _ForwardIterator
    remove_if(_ForwardIterator __first, _ForwardIterator __last,
          _Predicate __pred)
    {

      __first = _GLIBCXX_STD_A::find_if(__first, __last, __pred);

      if(__first == __last)                             // ^^^^^ here a copy is made
        return __first;
      _ForwardIterator __result = __first;
      ++__first;
      for(; __first != __last; ++__first)
        if(!bool(__pred(*__first)))
          {
            *__result = _GLIBCXX_MOVE(*__first);
            ++__result;
          }
      return __result;
    }

解决方法是让我们的仿函数静态化 set 成员:

struct comp {
    static set<int> s;
    comp() { s. clear(); }
    bool operator()(int i)
    {
        return !(s.insert(i)).second;
    }
};
set<int> comp::s;

但问题依然存在:

我们是否需要确保谓词仿函数的可能拷贝不会破坏我们的逻辑? 标准中是否有任何内容强制(或禁止)与此问题相关的某些行为?还是实现中的错误?

最佳答案

是的,标准没有指定谓词将被复制多少次,也没有说明谓词将以什么顺序应用于容器的元素。本质上,谓词的行为必须像 pure functions ;它们必须没有可观察的状态。1

所以 remove_if 在这里听起来不像是合适的算法。将 set 外部存储到仿函数之类的 hack 不会解决问题;你仍然会调用未定义的行为。


<子>1。有关更深入的讨论,请参阅 Scott Meyers 的 Effective STL 的第 39 项(“使谓词成为纯函数”) .

关于c++ - 是否允许标准库算法复制谓词参数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11071553/

相关文章:

c++ - 引用资料 |大数据意外崩溃

c++ - Clang Static Analyzer 在使用 protobuf 的 set_allocated_* 时提示内存泄漏

c++ - 在 cpp 文件中运行 asm 过程

c++ - CMake 3.13.2 似乎与 G++ 8.2.0 有问题

centos - ./configure 步骤中的错误。 (CentOS 7) 你的编译器没有必要的 C++17 支持

c++ - 动态选择要在 std::map 中使用的比较仿函数

Haskell fmap 通过自定义数据类型

c++ - sf::Sprites 拥有自己的位置和旋转背后的原因是什么?它混淆了我的组件/实体/系统

c++ - 构造函数和g++编译配方的问题

c++ - 在 C++ 中编写 structarray 映射仿函数的最清晰方法