Вопрос по visual-studio-2010, c++ – Как вставить дубликат элемента в вектор?

11

Я пытаюсь вставить копию существующегоvector элемент, чтобы удвоить его. Следующий код работал в предыдущих версиях, но не работает в Visual Studio 2010.

<code>#include <iostream>
#include <vector>

using namespace std;

int main(int argc, char* argv[])
{
   vector<int> test;
   test.push_back(1);
   test.push_back(2);
   test.insert(test.begin(), test[0]);
   cout << test[0] << " " << test[1] << " " << test[2] << endl;
   return 0;
}
</code>

Выход-17891602 1 2ожидаемый1 1 2.

Я выяснил, почему это происходит - вектор перераспределяется, и ссылка становится недействительной до того, как она будет скопирована в точку вставки. Старая Visual Studio, очевидно, делала вещи в другом порядке, доказывая тем самым, что одним из возможных результатов неопределенного поведения является правильная работа, а также доказывая, что на нее никогда не следует полагаться.

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

<code>   test.reserve(test.size() + 1);
   test.insert(test.begin(), test[0]);
</code>

Другой способ состоит в том, чтобы сделать копию из ссылки, чтобы не зависеть от ссылки, остающейся действительной:

<code>template<typename T>
T make_copy(const T & original)
{
    return original;
}

   test.insert(test.begin(), make_copy(test[0]));
</code>

Хотя оба работают, ни один не чувствует себя как естественное решение. Я что-то пропустил?

Работает ли приведение к int? Dan Nissenbaum
КСТАТИ VC11 Dev Preview дает1 1 2 для первого примера. Jesse Good
Я не думаю, что есть из чего выбирать из того, что вы предложили, вы можете принять значение до вставки, какint copy = test[0]; test.insert(test.begin(), copy); EdChum
@MarkRansom: этоbug report похоже на это. Jesse Good
@ Джесс, это меня не удивляет. Перегрузка Rvalueinsert был выбран, который выглядит как ошибка, которую они могли бы исправить. Код полностью отличается между той перегрузкой и той, которая принимает константную ссылку. Mark Ransom

Ваш Ответ

2   ответа
1

Я считаю, что это определенное поведение. В§23.2.3 в стандарте C ++ 2011 года в таблице 100 перечислены требования к контейнерам последовательностей, и для этого случая есть запись. Это дает пример выражения

a.insert(p,t)

гдеa это значениеX который представляет собой тип контейнера последовательности, содержащий элементы типаT, p является постоянным итератором дляa, а такжеt является lvalue или const rvalue типаX::value_typeт.е.T.

Утверждение для этого выражения:

Requires: T shall be CopyInsertable into X. For vector and deque, T shall also be CopyAssignable.
Effects: Inserts a copy of t before p.

Единственная релевантная цитата, специфичная для вектора, я могу найти в§23.3.6.5 пункт 1:

Remarks: Causes reallocation if the new size is greater than the old capacity. If no reallocation happens, all the iterators and references before the insertion point remain valid.

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

Что касается решения этой проблемы, я согласен с предложением @ EdChum просто сделать копию элемента и вставить эту копию.

Error: User Rate Limit ExceededtError: User Rate Limit Exceededa. Mark Ransom
4

vector::insert принимает в качестве второго параметра ссылку на значение, а не значение. Вам не нужен шаблон для создания копии, просто используйте конструктор копирования для создания другого объекта, который будет передан по ссылке. Эта копия остается действительной, даже если вектор изменен.

#include <iostream>
#include <vector>

using namespace std;

int main(int argc, char* argv[])
{
   vector<int> test;
   test.push_back(1);
   test.push_back(2);
   test.insert(test.begin(), int(test[0]));
   cout << test[0] << " " << test[1] << " " << test[2] << endl;
   return 0;
}
Error: User Rate Limit Exceeded Mark Ransom

Похожие вопросы