Как получить итераторы начала и конца у временного объекта без создания его промежуточной копии?

Рейтинг: 0Ответов: 1Опубликовано: 11.05.2023
// Пример кода надуманный, только для демонстрации проблемы!

#include <iostream>
#include <vector>

std::vector<int> TransformVector(const std::vector<int>& source_vector) {
    std::vector<int> transform_vector;
    for (int item : source_vector) {
        transform_vector.push_back(item * item);
    }
    return transform_vector;
}

std::vector<int> VectorVector_to_TransformVector(const std::vector<std::vector<int>>& vv) {
    std::vector<int> flat_vector;
    for (std::vector<int> v : vv) {
        std::vector<int> transform_vector = TransformVector(v);
        flat_vector.insert(flat_vector.end(), transform_vector.begin(), transform_vector.end());
    }
    return flat_vector;
}

void PrintVector(const std::vector<int>& v) {
    for (int number : v) {
        std::cout << number << " ";
    }
    std::cout << std::endl;
}

int main() {
    std::vector<std::vector<int>> vv = {
            {1,  2,  3,  4,  5},
            {6,  7,  8,  9,  10},
            {11, 12, 13, 14, 15},
            {16, 17, 18, 19, 20}
    };

    std::vector<int> flat_vector = VectorVector_to_TransformVector(vv);
    PrintVector(flat_vector);

    return 0;
}
// Вывод: 1 4 9 16 25 36 49 64 81 100 121 144 169 196 225 256 289 324 361 400

В функции VectorVector_to_TransformVector приходится создавать временный объект transform_vector, чтобы в следующей строке получить итераторы начала и конца последовательности. Потому что если сделать так:

flat_vector.insert(flat_vector.end(), TransformVector(v).begin(), TransformVector(v).end());

то функция TransformVector(v) будет вызвана 2 раза. Существуют ли какие-нибудь приемы, чтобы провернуть такой трюк, позволяющий получить итераторы начала и конца у временного объекта и не создавать этот объект два раза?

Ответы

▲ 1

Более того, в последнем вызове это формально итераторы к разным контейнерам.

Не проще ли, если уж так хочется отдельной функции, что-то вроде

for(auto x: TransformVector(v)) flat_vector.push_back(x);

Или вообще так, без создания временного контейнера:

std::vector<int> VectorVector_to_TransformVector(const std::vector<std::vector<int>>& vv) {
    std::vector<int> flat_vector;
    for (std::vector<int> v : vv) {
        for(auto x: v) flat_vector.push_back(x*x);
    }
    return flat_vector;
}

Не думаю, что insert будет быстрее, особенно если предварительно resize на весь размер всех исходных векторов сделать.

Еще можно посмотреть в сторону стандартных алгоритмов, например, transform.