Подтвердить что ты не робот

Предоставляет ли С++ 11 вектор <const T>?

Требования к контейнеру изменились с С++ 03 на С++ 11. Хотя С++ 03 имеет общие требования (например, конструктивность копирования и назначение для вектора), C ​​++ 11 определяет мелкозернистые требования к каждой операции с контейнером (раздел 23.2).

В результате вы можете, например, сохраните тип, который можно копировать, но не назначать - например, структуру с константным элементом - в векторе, пока вы выполняете только определенные операции, которые не требуют назначения (конструкция и push_back являются такими операциями; insert не является).

Мне интересно: это означает, что теперь стандарт позволяет vector<const T>? Я не вижу причин, по которым это не должно быть - const T, как структура с членом-константой, является типом, который является конструктивным, но не назначаемым, но я, возможно, что-то пропустил.

(Часть того, что заставляет меня думать, что я, возможно, что-то пропустил, состоит в том, что магистраль gcc сбой и ожоги, если вы пытаетесь создать экземпляр vector<const T>, но это нормально с vector<T>, где T имеет член const).

4b9b3361

Ответ 1

Нет, я считаю, что требования к распределителю говорят, что T может быть "неконстантным, не ссылочным типом объекта".

Вы не сможете многое сделать с вектором постоянных объектов. И const vector<T> был бы почти таким же.


Спустя много лет этот быстрый и грязный ответ все еще, кажется, привлекает комментарии и голоса. Не всегда наверху. :-)

Итак, чтобы добавить некоторые правильные ссылки:

Для стандарта С++ 03, который у меня есть на бумаге, в Таблице 31 в разделе [lib.allocator.requirements] сказано:

T, U any type

Не то чтобы любой тип на самом деле работал.

Итак, следующий стандарт, С++ 11, говорит в закрытом черновике в [allocator.requirements] и теперь в таблице 27:

T, U, C any non-const, non-reference object type

что очень близко к тому, что я изначально написал выше по памяти. Это также то, о чем был вопрос.

Однако в С++ 14 (черновик N4296) в таблице 27 теперь говорится:

T, U, C any non-const object type

Возможно, потому что ссылка, возможно, не тип объекта в конце концов?

И теперь в С++ 17 (проект N4659) это Таблица 30, которая говорит:

T, U, C any cv-unqualified object type (6.9)

Так что не только const исключается, но и volatile. Вероятно, старые новости в любом случае, и просто разъяснение.


Пожалуйста, также посмотрите информацию из первых рук Говарда Хиннанта, в настоящее время прямо ниже.

Ответ 2

Обновление

Под принятым (и правильным) ответом я прокомментировал в 2011 году:

Нижняя строка: мы не создали контейнеры для хранения const T. Хотя я и сделал подумайте. И мы очень приблизились к авария. Насколько я знаю, текущая точка пара перегруженных address функций-членов по умолчанию распределитель: Когда T есть const, эти две перегрузки имеют одинаковые подпись. Простым способом исправить это было бы специализация std::allocator<const T> и удалите одну из перегрузок.

С предстоящим проектом С++ 17 мне кажется, что мы теперь узаконили vector<const T>, и я также считаю, что мы сделали это случайно.: -)

P0174R0 удаляет перегрузки address с std::allocator<T>. P0174R0 не упоминает о поддержке std::allocator<const T> как части его обоснования.

Коррекция

В комментариях ниже T.C. правильно отмечает, что перегрузки address устарели, а не удалены. Виноват. Устаревшие члены не отображаются в 20.10.9, где std::allocator определен, но вместо этого отнесены к разделу D.9. Я забыл просканировать главу D для этой возможности, когда я разместил это.

Спасибо T.C. для исправления. Я предполагал удалить этот вводящий в заблуждение ответ, но, возможно, лучше оставить его с этой коррекцией, чтобы, возможно, это заставило кого-то другого неправильно интерпретировать спецификацию так же, как и я.

Ответ 3

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

Так что это не работает:

vector<const T> vec; 

Просто прочитайте другие ответы, чтобы понять, почему. И, как вы, возможно, догадались, это тоже не сработает:

vector<const shared_ptr<T>> vec;

T больше не const, но vector удерживает shared_ptr s, а не T s.

С другой стороны, это работает:

vector<const T *> vec;
vector<T const *> vec;  // the same as above

Но в этом случае const является объектом, на который указывает объект, а не сам указатель (что и хранит вектор). Это будет эквивалентно:

vector<shared_ptr<const T>> vec;

Это нормально.

Но если мы поместим const в конец выражения, теперь он превратит указатель в const, поэтому следующее не будет компилироваться:

vector<T * const> vec;

Немного запутанный, я согласен, но вы привыкаете к нему.

Ответ 4

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

vector<unique_ptr<const T>> vec;

Если это так, вы хотите обеспечить, чтобы только vec владела своими товарами. Или, если вы хотите динамически перемещать элементы в vec и в какой-то момент их вывести.

Как указано, семантика указателя const может вводить в заблуждение, но shared_ptr и unique_ptr - нет. const unique_ptr<T> является указателем константы, а unique_ptr<const T> является константой, как и следовало ожидать.