有状态函子和STL:未定义的行为
Stateful functors & STL : Undefined behaviour
我正在学习函数对象教程
复制下面的意大利面:
我无法理解以下内容:
谓词应始终作为无状态函数对象实现,以避免意外结果。无法保证算法内部复制谓词的频率。因此,将谓词实现为有状态函数对象可能会产生未被发现的结果
示例如下:
#include <iostream>
#include <vector>
#include <algorithm>
#include <iterator>
class predicate
{
public:
predicate(int condition) :
condition_(condition), state_(0) {}
bool operator()(int) { return ++state_ == condition_; }
private:
int condition_;
int state_;
};
int main()
{
std::vector<int> vec;
vec.push_back(1);
vec.push_back(2);
vec.push_back(3);
vec.push_back(4);
vec.push_back(5);
predicate p(2);
std::vector<int>::iterator pos =
std::remove_if(vec.begin(), vec.end(), p);
vec.erase(pos, v.end());
std::copy(vec.begin(), vec.end(),
std::ostream_iterator<int>(std::cout, " "));
return 0;
}
如果我正确理解(阅读)它,它正试图删除向量中标记为2的元素。remove_if算法返回容器的新端,并试图擦除所有端。
输出:
1 3 5
显然,不仅第二个元素被删除了,第四个元素也被删除了。这个问题的答案很简单,使用的算法"remove_if"在执行谓词时会在内部复制谓词。这个内部副本创建了一个包含其原始状态的新谓词对象
虽然我能读到似乎正在发生的事情,但我无法想象幕后发生的事情——即使是第四个元素也被移到了容器的末端。这与算法是单程还是多次有关?(如果有人能给我指明正确的方向,我也会很感激)
在旁注上,如果我评论擦除&注意输出。
1 3 5 4 5
是什么原因导致容器损坏?
该引号的含义应以面值表示。对于大多数STL算法,您不应该实现谓词函子,使其具有可观察状态(也称为"副作用"),因为:
- 容器上的迭代顺序没有被定义
- 该算法可以自由地复制函子
- 为了不损坏容器内容或崩溃,算法可能依赖无状态
将operator()
定义为const
是对自己强制执行此操作的最简单方法。
也有例外情况,如for_each
,上述情况均不适用。您可以在这里自由使用有状态函子。有关更多信息,请参阅这篇精彩的文章:http://drdobbs.com/cpp/184403769.
在幕后,STL实现的作者可以随心所欲地编写remove_if
(和其他算法),只要它符合标准规定的要求。没有真正的理由过于担心你看到的行为的确切原因,除了承认它是不明确的。如果您想了解具体情况,我只想看看您正在使用的STL实现中remove_if
的代码。
至于你的旁注;这不是"损坏",它只是remove_if
工作方式的产物(即使对于有效的谓词也会发生这种情况)。唯一的要求是pos
左侧的所有元素都是有效的(因为它们将被保留)。对于pos
以后存在的元素没有任何要求(请参见此处)。(Scott Meyers的"有效STL"第32章很好地解释了remove_if
(等等)为什么会这样做)。
- 编译C++时未定义的引用
- vscode g++链路故障:体系结构x86_64的未定义符号
- 如何修复此错误:未定义对"距离(浮点数,浮点数,浮点数,浮点数,浮点数)"的引用
- 我的项目不会像"undefined reference to `grpc::g_core_codegen_interface'"那样使用未定义的引用错误进行编译
- 不知道某个东西是否被忽略会引入未定义的行为吗
- 对C宏的未定义引用,但在定义它时会出现重新定义错误
- 未定义的引用在哪里
- 编译时的 CImg 库返回对"__imp_SetDIBitsToDevice"的未定义引用
- 对Py_Initialize()的未定义引用
- c++11评估顺序(未定义的行为)
- 使用mysql c++连接器的未定义引用
- 从python调用openMP共享库时,未定义opnMP函数
- 使用向量(STL)时,未定义的行为,请说明理性背后的以下代码输出
- 为什么STL中允许未定义的行为
- 从 STL 容器继承并删除"新"运算符以防止由于缺少虚拟析构函数而导致未定义的行为是否有意义?
- 为什么STL实现不使用断言来检测未定义的行为
- const_cast const STL 容器,它是未定义的行为
- STL Vector:临时调用 data() 时的未定义行为
- c++ 11 STL列表=和!= op未定义
- 有状态函子和STL:未定义的行为