Отправлено: 01.02.15 23:11. Заголовок: MS VC++ 2014: a std::accumulate's bug.
Реализация алгоритма std::accumulate в MS VC++ содержит неочевидный баг. Он неочевидный по той причине, что редко кто передает аргумент для параметра алгоритма init по ссылке, хотя это не воспрещается делать и на самом деле бывает очень удобно и эффективно с точки зрения работы алгоритма, так как не создаются временные объекты.
Я думаю, что этот баг имеет место во всех версиях компилятора MS VC++. По крайней мере он присутствует в онлайновой версии компилятора от 2014 года, которая маркируется как Compiler version: 19.00.22318(x86) Last updated: Nov
int main() { int a[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
for ( int x : a ) std::cout << x << ' '; std::cout << std::endl;
long long int acc = 0; std::cout << std::accumulate<decltype( std::begin( a ) ), long long int &> ( std::begin( a ), std::end( a ), acc ) << std::endl;
std::cout << acc << std::endl;
return 0; }
Здесь параметр init, который инициализируется аргументом acc явно указан, как имеющий тип ссылки long long int &. Поэтому объект acc после работы алгоритма должен быть равен сумме элементов массива a.
Однако данный код не компилируется компилятором MS VC++ из-за того, что реализация этого алгоритма в MS VC++ выполнена таким образом, что он вызывает другую внутреннюю функцию, где уже этот аргумент передается не по ссылке. Из-за этого и возникает ошибка компиляции.
Эта же программа успешно компилируется как компилятором GCC, так и компилятором Clang.
Я отослал сообщение о дефекте в Майкрософт, но последнее время там как-то вяло реагируют на подобные сообщения. То есть они остаются без ответа.
for ( int x : a ) std::cout << x << ' '; std::cout << std::endl;
for ( int x : b ) std::cout << x << ' '; std::cout << std::endl;
std::cout << std::endl;
long long int acc = 0;
std::cout << std::inner_product<decltype( std::begin( a ) ), decltype( std::begin( b ) ), long long int &> ( std::begin( a ), std::end( a ), std::begin( b ), acc ) << std::endl;
std::cout << acc << std::endl;
return 0; }
Хотя если запустить эту программу на www.ideone.com, используя компилятор GCC, или если запустить программу, используя clang 3.4, то она успешно скомпилируется и выведет на консоль следующий результат:
Отправлено: 11.02.15 08:33. Заголовок: Можно говорить про б..
Можно говорить про баги в этих алгоритмах при условии, что аккумулятор внутри них имеет тот же тип, что и инициализатор init. Однако если почитать стандарт C++, то окажется, что нигде в описании этих алгоритмов не говорится о том, какой тип будет иметь аккумулятор внутри алгоритмов. Вот, например, пункт из стандарта C++, где говорится о принципе работы алгоритма std::accumulate:
цитата:
1 Effects: Computes its result by initializing the accumulator acc with the initial value init and then modifies it with acc = acc + *i or acc = binary_op(acc, *i) for every iterator i in the range [first,last) in order.
Конечно подразумевается, что тип аккумулятора точно такой же, как тип инициализатора init, иначе алгоритмы будут иметь неопределенное поведение. Представьте для примера, когда инициализатор при вызове std::accumulate имеет тип double, в то время как аккумулятор внутри алгоритма определяется как имеющий тип int. В этом случае результат работы алгоритма может быть не тем, что вы ожидаете.
Очевидно, что в описании в стандарте C++ этих алгоритмов, std::accumulate и std::inner_product, следует явно указать, какой тип будет у аккумулятора, иначе это выглядит как дефект стандарта.
Поэтому соответствующее предложение по исправлению описания этих алгоритмов в стандарте C++ я направлю в Комитет по стандартизации..
Все даты в формате GMT
3 час. Хитов сегодня: 13
Права: смайлы да, картинки да, шрифты да, голосования нет
аватары да, автозамена ссылок вкл, премодерация откл, правка нет