VC ++ позволяет использовать константные типы для контейнеров STL. Зачем? - PullRequest
12 голосов
/ 09 февраля 2011

Контейнеры STL требуют, чтобы сохраненные значения были копируемыми и назначаемыми.const T, очевидно, не является присваиваемым типом для любого T, но я попытался использовать его (просто любопытно) и обнаружил, что он компилируется и, более того, ведет себя как присваиваемый тип.

vector<const int> v(1);
v[0] = 17;

Это успешноработает в Visual Studio 2008 и присваивает v [0] значение 17.

Ответы [ 2 ]

12 голосов
/ 09 февраля 2011

Это не ошибка в реализации, как предлагали другие.

Нарушение требований средства стандартной библиотеки C ++ не делает вашу программу плохо сформированной, она приводит к неопределенному поведению.

Вы нарушили требование о том, что тип значения, хранящийся в контейнере, должен быть копируемым и назначаемым (очевидно, const типы нельзя назначать), поэтому ваша программа демонстрирует неопределенное поведение.

Применимый язык из стандарта C ++ можно найти в C ++ 03 17.4.3.6 [lib.res.on.functions]:

В некоторых случаях (функции замены, функции-обработчики, операции над типами, используемые для создания экземпляров стандартных шаблонных компонентов библиотеки), стандартная библиотека C ++ зависит от компонентов, предоставляемых программой C ++. Если эти компоненты не соответствуют их требованиям, Стандарт не устанавливает требований к реализации.

В частности, эффекты не определены в следующих случаях:

...

  • для типов, используемых в качестве аргументов шаблона при создании экземпляра компонента шаблона, если операции над типом не реализуют семантику применимого подпункта Требования.

Реализация стандартной библиотеки Visual C ++ может делать с этим кодом все, что угодно, в том числе удалять или игнорировать const-квалификацию, и она по-прежнему соответствует стандартам.

1 голос
/ 09 февраля 2011

Это просто не должно работать. В §23.1 ¶ 3 указано, как вы сказали, что объекты, хранящиеся в контейнере, должны быть CopyConstructible (как указано в §20.1.3) и Assignable.

Требования Assignable для типа T таковы, что, будучи t и u типа T, вы можете сделать:

t = u

с T& в качестве возвращаемого значения и t, эквивалентным u в качестве постусловия. (§23.1 ¶4)

Таким образом, типы const явно не Assignable, так как выполнение t = u вызовет ошибку компиляции (§7.1.5.1 ¶5).

Полагаю, это ошибка в реализации Microsoft. g ++ в Linux испускает типичную ошибку шаблона в 25 каджиллион строк, если вы даже пытаетесь создать экземпляр vector<const int> (на всякий случай протестировано как с флагом * 1025, так и без него).

Кстати, это также подробно объясняется в этом IBM FAQ .

<ч />

Теоретически, как сказал @James McNellis, компилятору не требуется взрывать создание экземпляров вектора (если это неопределенное поведение, может произойти все что угодно - включая все, что работает нормально); однако в операторе присваивания есть нарушение стандарта, которое должно привести к ошибке компиляции.

Фактически, член operator[] возвращает vector<const int>::reference; что каждый должен быть lvalue T (§23.1-5 таблица 66); поскольку T имеет тип const, это будет const lvalue. Таким образом, мы переходим к (§7.1.5.1 )5), который определяет код, который пытается выполнить присваивание элементу const, как «плохо сформированный», и это требует ошибки компиляции или, по крайней мере, предупреждения, потому что присваивание -to- const - это диагностируемое правило (§1.4 ¶1-2) (оператор «диагностика не требуется» не указан).

<ч />

Окончательное редактирование

На самом деле, @Джеймс МакНеллис прав; как только вы вызвали неопределенное поведение путем создания экземпляра vector<const int>, обычные правила перестают иметь значение, поэтому реализация по-прежнему соответствует стандарту, что бы она ни делала - включая удаление const из типа элемента или генерацию обычных носовых демонов.

...