以下代码在XPSP3上的VC ++ 8下正确编译,但运行它会导致运行时错误。
我的标题如下:
#include <stdexcept>
#include <iterator>
#include <list>
template<typename T>
class test_generator
{
public:
typedef T result_type;
//constructor
test_generator()
{
std::generate_n( std::back_inserter( tests ), 100, rand );
value = tests.begin();
}
result_type operator()( void )
{
if( value == tests.end() )
{
throw std::logic_error( "" );
}
return *value++;
}
private:
std::list<T> tests;
typename std::list<T>::iterator value;
};
我的实现如下:
#include <functional>
#include <algorithm>
#include <iostream>
#include <deque>
#include "test.h"
int main()
{
test_generator<double> test;
std::deque<double> tests;
std::generate_n( std::back_inserter( tests ), 10, test );
return 0;
}
这个编译很好,它会生成一个异常(不是标题中定义的logic_error异常)。
如果我改变实现以使用函数而不是函子,它可以工作:
int main()
{
std::deque<int> tests;
std::generate_n( std::back_inserter( tests ), 10, rand );
return 0;
}
在这里使用仿函数有什么问题?
答案 0 :(得分:4)
test_generator
构造函数初始化value
迭代器以引用tests
列表中的第一个元素(它是test_generator
的成员)。
当您致电std::generate_n
时,会生成test
的副本(因为该对象是按值传递的)。在复制的对象中,value
迭代器引用原始对象中的tests
列表,而不是副本。
由于在Visual Studio STL实现中执行迭代器调试检查,因此会触发断言,因为从一个容器获取的迭代器不应与另一个容器的迭代器进行比较。
要解决此问题,您可以为test_generator
类实施复制构造函数,也可以将value
的初始化推迟到第一次调用operator()
。
答案 1 :(得分:0)
到目前为止,我还没有弄清楚导致异常的原因,但您可能希望return *value++
中有operator()
。 : - )