将自定义函子与std::generate_n()算法一起使用的正确方法

Correct way to use custom functor with std::generate_n() algorithm?

本文关键字:一起 算法 方法 自定义 std generate      更新时间:2023-10-16

以下代码在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;
}

在这里使用函子有什么问题?

test_generator构造函数初始化value迭代器以引用tests列表中的第一个元素(它是test_generator的成员)。

调用std::generate_n时,会生成test的副本(因为对象是按值传递的)。在复制的对象中,value迭代器指的是原始对象中的tests列表,而不是副本。

由于在Visual Studio STL实现中执行迭代器调试检查,因此这会触发断言,因为从一个容器获得的迭代器不应与另一个容器中的迭代程序进行比较。

为了解决这个问题,您可以为test_generator类实现一个复制构造函数,或者将value的初始化推迟到第一次调用operator()

到目前为止,我还没有弄清楚是什么导致了异常,但您可能希望在operator()中包含return *value++。:-)