Следующий код правильно компилируется под 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;
}
Что плохого в использовании здесь функтора?





Я пока не выяснил, что вызывает исключение, но вы можете захотеть иметь return *value++ в вашем operator(). :-)
Я не говорю, что * value ++ отличается от * (value ++), просто в приведенном выше примере кода этого не было. Но хорошо, что в вашем фактическом коде (который, кстати, вы должны вставить) он есть. :-)
извините об этом ... это на самом деле мой настоящий код ... Я просто не уловил этого, пока не опубликовал.
Конструктор test_generator инициализирует итератор value для ссылки на первый элемент в списке tests (который является членом test_generator).
Когда вы вызываете std::generate_n, создается копия test (поскольку объект передается по значению). В скопированном объекте итератор value ссылается на список tests в исходном объекте, а не на копию.
Из-за проверок отладки итератора, выполняемых в реализации Visual Studio STL, это вызывает утверждение, поскольку итератор, полученный из одного контейнера, не должен сравниваться с итератором из другого контейнера.
Чтобы решить эту проблему, вы можете реализовать конструктор копирования для вашего класса test_generator или отложить инициализацию value до первого вызова operator().
Перемещена инициализация значения в список инициализации и реализован конструктор копирования, это устранило проблему.
изменение * (значение ++) на * значение ++ не повлияло.