Инкремент итератора, приводящий к различным результатам в clang и gcc - PullRequest
1 голос
/ 30 апреля 2020

Я обнаружил странную проблему в следующем фрагменте кода, которая привела к другим результатам.

Apple Clang (протестировано с 3.8.0 и 11.0) возвращает ожидаемое значение 10, но g cc (протестировано с 5.4 .0 и 9) возвращает 12.

#include <functional>
#include <iostream>
#include <vector>

int acc(std::function<int(int, int)> func, std::vector<int> operands) {
    auto it = operands.begin();
    int result = func(*it, *(++it));  // <-- causing issue, ++it not working as expected
    if (operands.size() > 2) {
        for (++it; it!=operands.end(); ++it) {
            result = func(result, *it);
        }
    }
    return result;
}

int main() {
    std::cout << acc([](int a, int b){ return a+b; }, {3, 5, 2}) << std::endl;
}

Это можно воспроизвести, например, используя rextester.com .

Во время отладки я обнаружил, что приращение итератора ++it похоже проблема. Замена на it+1 с последующим оператором it = it + 1 приводит к ожидаемому результату в обоих компиляторах. Но почему это компилируется по-разному среди компиляторов?

1 Ответ

1 голос
/ 30 апреля 2020

Но почему это по-разному обрабатывается в компиляторах?

Поскольку до C ++ 17 не указывалось, в каком порядке оцениваются аргументы функции порядка.

Я бы предложил не вызывать func при инициализации result.

int acc(std::function<int(int, int)> func, std::vector<int> operands) {
    if (operands.empty()) throw std::out_of_range();

    auto it = operands.begin();
    int result = *it;
    for (++it; it!=operands.end(); ++it) {
        result = func(result, *it);
    }
    return result;
}

Обратите внимание, что std::function часто является избыточным для передачи функций. Стандартная библиотека предпочитает шаблонные функции высшего порядка, например, копирование std::accumulate

template<class BinaryOperation >
int acc(BinaryOperation op, std::vector<int> operands)

, где BinaryOperation - это любой тип функции, который может вызываться как int(int, int), например тип вашей лямбды

...