Позволяет ли C ++ 11 вектор? - PullRequest
62 голосов
/ 05 августа 2011

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

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

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

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

Ответы [ 4 ]

41 голосов
/ 05 августа 2011

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

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


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

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

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

T, U any type

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

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

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

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

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

T, U, C any non-const object type

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

А теперь в C ++ 17 ( черновик N4659 ) именно таблица 30говорит:

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

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


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

26 голосов
/ 23 сентября 2016

Обновление

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

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

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

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

Исправление

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

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

4 голосов
/ 08 октября 2016

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

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

vector<const T> vec; 

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

vector<const shared_ptr<T>> vec;

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

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

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;

Немного смущает, согласен, но вы к этому привыкли.

2 голосов
/ 05 января 2018

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

vector<unique_ptr<const T>> vec;

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

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

...