2016-11-04 5 views
1

Я пытаюсь std::move элемент из std::set, а затем удалить его из набора:std :: перемещать элементы из контейнера STL?

std::set<some_type> the_set; 
some_type item; 

for (auto iter = the_set.begin(); iter != the_set.end(); iter++) 
{ 
    auto miter = std::make_move_iterator(iter); 
    item = std::move(*miter); 
    the_set.erase(iter); 
    break; 
} 

компилятор не любит его, хотя (MSVC 2015):

error C2280: 'some_type &some_type::operator =(const some_type &)': attempting to reference a deleted function 

Похоже, что вместо этого пытается использовать конструктор копирования, чего я не хочу. Как я могу использовать конструктор перемещения? (Я пробовал move_iterator из отчаяния, не уверен, что это правильное решение здесь).

ответ

3

std::set Итераторы эффективно const итераторы (в C++ 11 и более поздних версиях). Таким образом, вы не можете изменить их и сломать set.

И вы не можете перейти от const&&. Таким образом, вы не можете перейти от set.

C++ 17 позволит вам это сделать, но via a different API (PDF). В принципе, вы должны extract the node itself from the set, затем переместите объект в узле, а затем уничтожьте узел (позволив ему упасть со стека). Я считаю, что код будет выглядеть примерно так:

for (auto iter = the_set.begin(); iter != the_set.end(); iter++) 
{ 
    auto node = the_set.extract(iter); 
    item = std::move(node.value()); 
    break; 
} 
+0

Поскольку в моем случае я удаляю сразу после перемещения, могу ли я использовать const const для выполнения перемещения? Я знаю, что это, наверное, немного взломано ... – atanamir

+2

@atanamir: Наверное, нет. В тот момент, когда вы «перемещаете» его (и что-то действительно мутирует его содержимое для обмена данными), «set» находится в противоречивом состоянии (инвариант сортировки, вероятно, нарушен). Алгоритмы, которые он использовал бы для удаления элемента, полагаются на этот инвариант (черт возьми, они полагаются на объект, находящийся в пригодном для использования состоянии для таких вещей, как 'operator <' calls, и единственная гарантия, которую вы получаете после того, как вы переехали из чего-то, что можно переназначить или уничтожить его, больше ничего не разрешено, у него могут быть указатели «NULL», которые являются незаконными в противном случае). Не пытайтесь это делать. – ShadowRanger

+2

@atanamir: Это говорит о том, что C++ 17 представляет ['std :: set :: extract'] (http://en.cppreference.com/w/cpp/container/set/extract), который позволил бы что вы пытаетесь сделать (предполагая, что я правильно его читаю). – ShadowRanger

Смежные вопросы