std::vector‹std::string› вместо этого вставить пустую строку

В Visual Studio 2013 я создал std::vector и сохранил в нем несколько строк. Затем я хочу сделать копию некоторой строки в векторе и добавить их в конец (допустим, переместить их в конец, после того, как вставка сделает стирание), но используя метод вставки, я увидел только пустые строки в конце, очень странный. Я воспроизвел его с помощью простого тестового кода,

std::vector<std::string> v;
std::string s = "0";
for (int i = 0; i < 7; ++i)
{
    s[0] = '0' + i; 
    v.push_back(s);
}
v.insert(v.end(), v.begin(), v.begin() + 3);
for (std::string& s : v) 
    std::cout << "\"" << s.c_str() << "\" ";

Я получаю там "0" "1" "2" "3" "4" "5" "6" "" "" ""

Я отладил метод вставки, внутри метода _Insert(..) векторного класса, он сделал некоторое перераспределение памяти, перемещение/перемещение памяти и так далее.

Первый вызов _Umove перемещает все 7 строк в новую выделенную память, я думаю, что вызывается std::move, в старой памяти осталась пустая строка.

Затем методом _Ucopy попробуйте скопировать 3 элемента, но из старой памяти, в результате прикрепляются 3 пустые строки. Есть еще один вызов _Umove, я не уверен, для чего он нужен. После всего этого старая память освобождается, а новая память прикрепляется к вектору.

Использование скалярного типа, такого как int, не приводит к неправильному выводу, поскольку память копируется, а std::move не вызывается.

Я делаю что-то не так, или это ошибка MS Visual Studio STL?


person Tiger Hwang    schedule 21.11.2016    source источник


Ответы (1)


Из этот std::vector::insert справочник:

Вызывает перераспределение, если новое size() больше старого capacity(). Если новое значение size() больше, чем capacity(), все итераторы и ссылки становятся недействительными

[Выделено мое]

Вы добавляете элементы в вектор при повторении вектора с помощью итераторов. Поскольку это может привести к перераспределению вектора, ваши итераторы будут признаны недействительными. Это приведет к неопределенному поведению.

person Some programmer dude    schedule 21.11.2016
comment
Насколько я понимаю, перераспределение приводит к тому, что итераторы и ссылка становятся недействительными, что должно произойти после возврата вставки. Любой итератор и ссылка на вектор инвалидируются, но это происходит во время вызова, мне это странно. Я пытаюсь зарезервировать место перед вставкой, тогда это работает. Это всего лишь обходной путь. Позже попробую с другим компилятором. - person Tiger Hwang; 21.11.2016
comment
@TigerHwang Вы передаете два итератора функции insert. Как только функция insert освобождает место для новых элементов, те итераторы, которые вы передаете, становятся недействительными. Использование другого компилятора не решит вашу проблему. Резервирование места - единственное решение. - person Some programmer dude; 21.11.2016
comment
Моя цель — переместить некоторые строки в векторе в конец, поэтому я попробовал другой метод std::move(v.begin(), v.begin() + 3, v.end()). Это вызывает ошибку утверждения из-за того, что итератор + смещение выходит за пределы допустимого диапазона. С std::move(v.begin(), v.begin() + 3, v.end() - 3) он не терпит неудачу, но результат не тот, который я хочу. Любое предложение? - person Tiger Hwang; 22.11.2016
comment
@TigerHwang В этом случае я предлагаю использовать обычный цикл for, который повторяется три раза. В цикле получите value первого элемента, удалите первый элемент и добавьте значение сзади. - person Some programmer dude; 22.11.2016
comment
Спасибо, я просто помню, что метод rotate в std должен помочь. - person Tiger Hwang; 22.11.2016
comment
@TigerHwang Или это... :) - person Some programmer dude; 22.11.2016