Как сохранить позицию в векторе для последующей вставки? - PullRequest
1 голос
/ 27 сентября 2019

Я хочу удалить данные из вектора, использовать их, а затем снова вставить их в вектор в той же позиции.

Я собираюсь использовать это как кэш для «отправляемых вещей», вставляя зановов случае «невозможности отправки», пока новинки имеют более высокий приоритет.Только один поток удалит вещи из этого кэша, так что не беспокойтесь о его меньшем размере, чем изначально, другие потоки смогут только его увеличить.

Я пробовал этот простой тестовый код, но нашел странный результатЯ хотел бы понять, почему это произошло и как это исправить:

void printVector(std::vector<int> &vector) {
    for (auto i : vector) {
        std::cout << i << "\n";
    }
    std::cout << std::endl;
}


int main() {
    std::vector<int> states_cache {1, 2, 3};

    printVector(states_cache); // prints: 1 2 3
    auto pos = states_cache.end();
    int i = states_cache.back();
    states_cache.pop_back();

    std::cout << "i1: " << i << std::endl;
    printVector(states_cache); // prints: 1 2 

    states_cache.push_back(4);
    states_cache.push_back(5);
    states_cache.push_back(6);
    printVector(states_cache);  // prints: 1 2 4 5 6 


    states_cache.insert(pos - 1, i); // Here I can see at the debugger that pos inner memory structure value changes from 129 to 4, whatever this means

    printVector(states_cache); // prints: 33 1 2 4 5 6
}

последние printVector отпечатки:

33 1 2 4 5 6

Я вижу, что первый элемент, оцениваемый в printVector, это число 33, поэтому не печатается дважды число 3.

Я ожидал, что оно будет:

1 2 3 4 5 6

Как будто 3 был удален, «использован», а затем снова вставлен в то же положение, что и раньше.

Ответы [ 2 ]

2 голосов
/ 27 сентября 2019

auto pos = states_cache.end(); В этот момент pos - это не позиция, а итератор для вектора.

Каждый раз, когда вы помещаете элементы в вектор, конец итератора вектора- который ваш pos в настоящее время содержит - недействителен, поэтому после этих нажатий итератор pos больше не действителен и не пригоден для использования.

Если вы хотите вставить элемент в положение, в котором он изначально находился, выпридется запомнить индекс удаляемого элемента, а затем преобразовать этот индекс в итератор для вызова insert.

Чтобы получить индекс, вы можете использовать std::distance с двумя итераторами - один изэлемент, второй в начале вектора.Например, чтобы получить индекс последнего элемента в векторе, вы можете использовать

auto ix = std::distance(vec.begin(), vec.end()) - 1;

Также обратите внимание, что предполагается, что вектор не пустой.

1 голос
/ 27 сентября 2019

Проблема в том, что векторные итераторы могут быть недействительными в случае перераспределения: они в основном являются указателями на память, в которой находятся векторные данные. Когда вы делаете push_back, вектор может быть вынужден перераспределить на другой адрес в памятиТаким образом, любой имеющийся у вас итератор больше не может быть использован.

Вам необходимо сохранить в качестве позиции числовой индекс, а не итератор.

Чтобы вставить обратно элемент, который вы затем можете сделать

states_cache.insert(states_cache.begin() + index, element);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...