Это класс, который содержит const std::vector и хранит его минимальное и максимальное значение:

#include <vector>
#include <algorithm>

class MyClass {

public:
    const std::vector<int> v;
    const std::pair<int, int> minmax_v;

    MyClass(const std::vector<int> & v_init)
    : v(v_init),
    minmax_v(*(std::min_element(v.begin(), v.end())), *(std::max_element(v.begin(), v.end()))) {}

};

Можно как-то использовать std::minmax_element для инициализации minmax_v? Идея состоит в том, чтобы повысить производительность.

Конечно, можно использовать std::minmax_element в теле конструктора и отбросить const вместо minmax_v, но это тоже неправильно.

4
Tim 13 Мар 2018 в 11:59

2 ответа

Лучший ответ

Используйте конструктор делегирования, чтобы получить пару результатов minmax_element() в одном аргументе:

class MyClass {
public:
    const std::vector<int> v;
    const std::pair<int, int> minmax_v;

    MyClass(const std::vector<int> & v_init)
    : MyClass(v_init, std::minmax_element(v_init.begin(), v_init.end()))
    {}

private:
    MyClass(const std::vector<int> & v_init,
            std::pair<std::vector<int>::const_iterator,
                      std::vector<int>::const_iterator> p)
        : v(v_init), minmax_v(*p.first, *p.second)
    {}

};
7
Jarod42 13 Мар 2018 в 13:03

Поскольку вы просите об этом для повышения производительности, я хочу указать, что в этом случае может быть быстрее использовать пользовательский цикл. В вашем примере есть две операции, каждая из которых выполняет итерацию по вектору: инициализация v и std::minmax_element обе проходят по входному вектору. Повторение дважды кажется не оптимальным, поэтому может быть лучше объединить операции в один цикл.

class MyClass {
private:
    MyClass(std::tuple<int, int, std::vector<int>>&& x): v( std::get<2>(x) ), minmax_v( std::get<0>(x), std::get<1>(x)) {

}

    static std::tuple<int, int, std::vector<int>> init(std::vector<int> const& v_init) {
        std::vector<int> v;
        v.reserve(v_init.size());
        int min = v_init.front();
        int max = v_init.front();
        for(auto const& x: v_init) {
            v.push_back(x);

            if (min > x) {
                min = x;
            }

            if (max < x) {
                max = x;
            }
        }

        return std::make_tuple(min,max, std::move(v));
    }

public:
    const std::vector<int> v;
    const std::pair<int, int> minmax_v;

    MyClass(const std::vector<int> & v_init): MyClass(init(v_init)) {}
};

Я предполагаю, что входной вектор не пустой, поскольку исходный пример также разыменовывает результат std::min_element и std::max_element, не сравнивая его с v_init.end(). Поскольку элементы const не могут быть инициализированы в теле конструктора, мне пришлось придумать обходной путь, используя вспомогательный кортеж.

Я также хочу сказать, что, вероятно, предпочел бы использовать алгоритмы STL вместо написанного от руки цикла, пока не увижу проблемы с производительностью. Современные компиляторы, вероятно, объединяют два цикла в один цикл и создают эффективный код.

1
Jens 13 Мар 2018 в 16:16