Почему стандарт C ++ запрещает контейнеры элементов const? [Дубликат]

Классы более приятные, но если прецедент ограничен, например. один метод тела, расточительно его создавать. Если у вас есть класс Pair , вы можете специализироваться на этом, не создавая новый класс.

51
задан HighCommander4 2 March 2015 в 04:59
поделиться

4 ответа

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

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


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

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

Для стандарта C ++ 03, который у меня есть на бумаге, Table 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. В любом случае, старые новости и просто разъяснение.


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

33
ответ дан Bo Persson 16 August 2018 в 00:57
поделиться
  • 1
    Итог: мы не проектировали контейнеры для хранения const T. Хотя я и подумал. И мы пришли действительно близко к тому, чтобы делать это случайно. Насколько мне известно, текущая точка привязки - это пара перегруженных функций address-члена в распределителе по умолчанию: Когда T const, эти две перегрузки имеют одну и ту же подпись. Простым способом исправить это было бы специализировать std::allocator<const T> и удалить одну из перегрузок. – Howard Hinnant 5 August 2011 в 14:28
  • 2
    @ HighCommander4: Я не уверен. В libc ++ я могу построить вектор (даже непустой) с кооперативным распределителем. Я не могу делать что-либо еще (не const const) с ним. Я не уверен, соответствует ли это вашим определениям «работает». Я также не уверен, если я невольно воспользуюсь расширением. Чтобы быть уверенным, мне нужно будет вкладывать в этот вопрос гораздо больше времени. Я сделал такие инвестиции раньше времени, но это было несколько лет назад, и многое изменилось в промежуточный период. Если это сработает, это не по дизайну со стороны комитета. – Howard Hinnant 5 August 2011 в 20:55
  • 3
    @Howard: Я не могу представить никаких технических препятствий для возможности push_back. Но если это не разрешено дизайном, нам лучше не делать этого. Мне было просто любопытно. – HighCommander4 5 August 2011 в 21:19
  • 4
    Кэш часто является изменяемым контейнером неизменяемых объектов, и сортированный вектор часто является альтернативой карте, поэтому я не согласен с тем, что вектор объектов const малопривлекателен. – Chris Oldwood 17 May 2013 в 11:13
  • 5
    Это позор. Я использовал std::vector<const T> именно потому, что он очень похож на const std::vector<T>, но без отрицательных последствий последнего для класса, который его удерживает. Фактически, std::vector<const T> ТОЧНО, что мне нужно семантически в большинстве случаев, когда я использую vector. Теперь я должен отказаться const - вместе с надежностью, которую он обеспечивает. – Violet Giraffe 24 June 2016 в 07:21

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

vector<unique_ptr<const T>> vec;

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

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

2
ответ дан Daniel Gouvêa 16 August 2018 в 00:57
поделиться

Обновить

В соответствии с принятым (и правильным) ответом я прокомментировал в 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> как части его обоснования.

Коррекция

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

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

20
ответ дан Howard Hinnant 16 August 2018 в 00:57
поделиться
  • 1
    Это довольно забавно! (Теперь нам просто нужно быть очень спокойным об этом, и пусть он проскользнет на C ++ 17, никто не заметит :)) – HighCommander4 23 September 2016 в 15:29
  • 2
    Не таблица требований распределителя все еще просто запрещает ее прямо? Независимо от того, что P0174R2 (который является измененной версией), только осуждает, а не удаляет address. – T.C. 27 September 2016 в 21:01
  • 3
    @ T.C .: Вы абсолютно правы. Спасибо за исправление. – Howard Hinnant 27 September 2016 в 21:21
  • 4
    Итак, c ++ 2x, наконец, разрешит vector<const T> :) – M.M 27 September 2016 в 22:27
  • 5
    Ответ «Нижняя линия: мы не проектировали контейнеры для хранения const T». предполагает, что целью является то, что контейнер должен содержать «const T». Однако можно утверждать, что целью пользователя является ограничение операций над контейнером - так, например, 'back ()' возвращает & quot; const T & amp; & quot; - независимо от содержимого контейнера. – Hans Olsson 7 October 2016 в 12:34

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

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

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;

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

3
ответ дан Lucio Paiva 16 August 2018 в 00:57
поделиться
Другие вопросы по тегам:

Похожие вопросы: