#c #visual-studio #stl #set
#c #visual-studio #stl #установить
Вопрос:
У меня есть следующий код, в котором я сохраняю std::set итераторов в контейнере STL int
s и стираю элемент по ключу (где ключ является итератором для контейнера STL). Код компилируется и выполняется как ожидалось (компилятор — VC 2008), если контейнер является std::vector, но не компилируется, если контейнер является std::list
using namespace std;
typedef vector< int > Container; //--> fails to compile if 'vector' is changed to 'list'
typedef Container::iterator IntIt;
set< IntIt > itSet;
Container c;
c.push_back (1);
c.push_back (2);
c.push_back (3);
IntIt it = c.begin ();
itSet.insert (it );
itSet.insert (it );
itSet.erase (c.begin ()); //--> The problematic line
Ошибка компиляции:
c:Program Files (x86)Microsoft Visual Studio 9.0VCincludefunctional(143) : ошибка C2784: ‘bool std::operator <(const std::_Tree<_Traits> amp;,const std::_Tree<_Traits> amp;)’ : не удалось вывести аргумент шаблона для ‘const std::_Tree<_Traits> amp;’ из ‘const IntIt’
Итак, мне кажется, ошибка заключается в том, что компилятор интерпретирует один из операторов шаблона <
as smaller than
, но я не могу понять, почему или как это исправить.
Комментарии:
1. В VS2008 произошел сбой, я думаю, это зависит от
list::iterator
реализации.2. На мой взгляд, это действительно плохая идея иметь
std::set
of iterator (of vector), потому что, как только вектор изменит свои размеры, все итераторы в наборе будут признаны недействительными, и вы никогда не знаете, когда вектор изменит свои размеры. Я не говорю, что невозможно узнать, когда это произойдет, но было бы неэлегантно иметь такой дизайн, который требует этих знаний. Если вы сообщите нам цель относительно того, что именно вы пытаетесь сделать, возможно, мы могли бы предложить несколько лучших решений.3. Что вы на самом деле пытаетесь сделать? Набор итераторов в вектор будет содержать только то, что вы получаете при увеличении от
c.begin()
доc.end()
.
Ответ №1:
Проблема вызвана тем, что list::iterator
не определено сравнение. Тип значения an std::set
требует строгого слабого упорядочения.
A vector
поддерживает итераторы произвольного доступа, которые имеют порядок. Список требуется только для поддержки двунаправленных итераторов, у которых нет упорядочения (конечно, реализация может свободно поддерживать итераторы произвольного доступа и для списков, поэтому на некоторых компиляторах это может сработать).
Чтобы исправить это, вам пришлось бы написать функцию сравнения самостоятельно. Проблема в том, что единственным способом определить порядок двух итераторов в list
было бы переходить от одного к другому, что требует линейного времени.
Комментарии:
1. Итак, как получилось, что это позволяет мне вводить значения без определенного оператора сравнения?
2. @Итамар Кац: Так ли это? На VS2008
insert
также выдает ошибку.3. Хорошо, это не так… Я слишком поторопился с вопросом.
4. Что касается вашего комментария о написании оператора сравнения — поскольку я не возражаю против порядка элементов в std :: set, я могу использовать любое произвольное сравнение, не обязательно порядок двух итераторов (я прав ..?)
5. @Itamar: Вы можете использовать любой строгий слабый порядок. Вы могли бы, например, упорядочить по адресам объектов, на которые ссылается итератор. Тем не менее, вы можете рассмотреть возможность использования
boost::hash_set
из Boost. Неупорядоченный .