Правильный способ использовать пользовательский функтор с алгоритмом std :: generate_n ()? - PullRequest
2 голосов
/ 23 октября 2008

Следующий код правильно компилируется в VC ++ 8 на XPSP3, но его запуск вызывает ошибку во время выполнения.

Мой заголовок выглядит так:

#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;
}

Что не так с использованием функтора здесь?

Ответы [ 2 ]

4 голосов
/ 24 октября 2008

Конструктор test_generator инициализирует итератор value для ссылки на первый элемент в списке tests (который является членом test_generator).

Когда вы вызываете std::generate_n, создается копия test (поскольку объект передается по значению). В скопированном объекте итератор value ссылается на список tests в исходном объекте, а не на копию.

Из-за проверок отладки итератора, выполненных в реализации Visual Studio STL, это вызывает утверждение, поскольку итератор, полученный из одного контейнера, не следует сравнивать с итератором из другого контейнера.

Чтобы решить эту проблему, вы можете либо реализовать конструктор копирования для вашего test_generator класса, либо отложить инициализацию value до первого вызова operator().

0 голосов
/ 24 октября 2008

Я до сих пор не выяснил, что является причиной исключения, но вы можете пожелать иметь return *value++ в вашем operator(). : -)

...