Лучший способ скопировать большой контейнер в C ++ - PullRequest
2 голосов
/ 26 февраля 2020

Меня интересует наилучший способ производительности копирования больших контейнеров. Представьте, что у каждого есть векторный контейнер, в котором хранится, например, 60 000 000 записей (возможно, long double) или намного больше значений. Теперь, если кто-то решает, например, ODE (обыкновенное дифференциальное уравнение), необходимо (на основе используемого алгоритма) сделать копию старых значений, которые используются для расчета, чтобы обновить новые значения. Следующий (воображаемый) пример:

// This container is inside a class (so it is initialized and stored at the memory during runtime)
vector<long double> Y(60000000,0);

// Later on in a function
void solve()
{
    for(i=0; i<iMax, ++i)
    {
        // Make a copy for the field one is solving for (depending on the algorithm in use if it is needed)
        // The following is not the best solution as we allocate and deallocate YprefIter for each
        // Iteration; imagine iMax = 1000000
        vector<long double> YprefIter = Y;
        ...

        // Do some analysis (simplified); 
        Y = something * YprefIter * something + anything

        // As YprefIter might be used somewhere else, we cannot update Y only
        Y = YprefIter + Y * whatever
        ...
    }
}

Конечно, принимая vector<long double> YprefIter перед скобками, нам не нужно создавать и уничтожать объект для каждой итерации. Это, безусловно, лучший выбор:

// This container is inside a class (so it is initialized and kept)
vector<long double> Y(60000000,0);

// Later on in a function
void solve()
{
    vector<long double> YprefIter (Y.size(), 0);

    for(i=0; i<iMax, ++i)
    {
        // Make a copy for the iteration algorithm
        // Better solution as we get rid of the memory allocation and deallocation 
        YprefIter = Y;
        ...
    }
}

Однако я спрашиваю себя, есть ли более продвинутые решения вокруг. Например, использовать move semantics в таком примере или делать другие вещи, которые я не знаю о вещах, которые были бы намного лучше в смысле использования реальных разработок. Я ожидал бы, что мои вышеупомянутые стратегии не современны. Мне просто пришло в голову, что я могу использовать два указателя при переключении указательного объекта для каждой итерации. Однако это всего лишь мысль, я не проверял здесь логи c, но идея в том, что мне не нужно ничего копировать; может быть, лучшее решение, и если такие вещи сработают, я уверен, что что-то уже реализовано в c ++ :)

// This container is inside a class (so it is initialized and kept)
vector<long double> Y(60000000,0);

// Later on in a function
void solve()
{
    // Create the second object
    vector<long double> YprefIter (Y.size(), 0);

    // Pointer 1 and Pointer 2
    vector<long double>* pToY = NULL;
    vector<long double>* pToYPref = NULL

    // Set pointer pToY to point to Y
    pToY = &Y;

    for(i=0; i<iMax, ++i)
    {
        // Switch the Pointer fields for each iteration
        if (i%2)
        {
            pToY = &Y;
            pToYPrefIter = &YPrefIter;
        }
        else
        {
            pToY = &YPrefIter;
            pToYPrefIter = &Y;
        }

        // Work with the pointers afterwards
        ...
    }
}

Любой комментарий приветствуется. Tobi

1 Ответ

3 голосов
/ 26 февраля 2020

Первый фрагмент кода выглядит примерно так:

for(i=0; i<iMax, ++i)
{
    vector<long double> YprefIter = Y;
    //  ...
    Y = f(YprefIter);
    //  ...
}

В этом случае вы можете просто поменять местами два вектора:

// Initialize Y_old
vector<long double> Y_old = whatever(),
                    Y;
for(i=0; i<iMax, ++i)
{
    //  ...
    Y = f(Y_old);
    //  ...
    // The swap is implemented in terms of moves, it doesn't copy the values.
    std::swap(Y_old, Y);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...