将自定义函子与 std::generate_n() 算法一起使用的正确方法?
以下代码在 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;
}
这里使用函子有什么问题?
The following code compiles correctly under VC++ 8 on XPSP3, but running it causes a runtime error.
My header looks like:
#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;
};
My implementation looks like:
#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;
}
This compiles fine, it generates an exception (not the logic_error exception defined in the header).
If I change the implementation to use a function instead of a functor, it works:
int main()
{
std::deque<int> tests;
std::generate_n( std::back_inserter( tests ), 10, rand );
return 0;
}
What's wrong with using a functor here?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
test_generator
构造函数初始化value
迭代器以引用tests
列表中的第一个元素(它是test_generator
的成员) >)。当您调用
std::generate_n
时,会生成test
的副本(因为该对象是按值传递的)。 在复制的对象中,value
迭代器引用原始对象中的tests
列表,而不是副本。由于在 Visual Studio STL 实现中执行迭代器调试检查,这会触发断言,因为从一个容器获取的迭代器不应与来自另一容器的迭代器进行比较。
要解决此问题,您可以为
test_generator
类实现复制构造函数,或者推迟value
的初始化,直到第一次使用operator()
被调用。The
test_generator
constructor initialises thevalue
iterator to reference the first element in thetests
list (which is a member oftest_generator
).When you call
std::generate_n
, a copy of thetest
is made (because the object is passed by value). In the copied object, thevalue
iterator refers to thetests
list in the original object, not the copy.Because of the iterator debugging checks performed in the Visual Studio STL implementation, this triggers an assertion, because an iterator obtained from one container should not be compared against an iterator from another container.
To fix the problem, you could either implement a copy constructor for your
test_generator
class, or defer initialisation ofvalue
until the first timeoperator()
is invoked.到目前为止,我还没有弄清楚是什么导致了异常,但您可能希望在
operator()
中使用return *value++
。 :-)I haven't figured out what's causing the exception so far, but you may wish to have
return *value++
in youroperator()
. :-)