std::size_t или std::vector‹Foo›::size_type?

Когда я зацикливаюсь на std::vector<Foo> (или каждом контейнере, имеющем итератор произвольного доступа), я использую целочисленную переменную без знака i. Если я хочу соблюдать норму, должен ли я использовать std::size_t или тип, заданный самим контейнером: std::vector<Foo>::size_type?

Если я выбрал std::size_t (из соображений удобочитаемости), могу ли я быть уверен, что каждая реализация каждого контейнера в пространстве имен std использует std::size_t как size_type ?

Примечание. Я использую только C++98 (из соображений совместимости).


person Caduchon    schedule 18.07.2017    source источник
comment
Нет, ты не можешь быть уверен. Если вы хотите избежать возможного сужающего преобразования, используйте предоставленный тип контейнера.   -  person StoryTeller - Unslander Monica    schedule 18.07.2017
comment
Одна забавная вещь, которую вы могли бы иметь, это size_t быть определением типа unsigned long, а std::vector::size_type может быть unsigned long long на 64-битной машине Linux. Оба имеют ширину 64 бита и будут иметь одинаковый диапазон, но они не одного типа. (пример)   -  person NathanOliver    schedule 18.07.2017
comment
Вы можете использовать класс шаблона, который выбирает, какой тип использовать, в зависимости от того, имеют ли std::size_t и std::vector<T>::size_type одинаковый размер (я не могу сейчас попытаться реализовать его, но я уверен, что это выполнимо).   -  person nefas    schedule 18.07.2017
comment
@NathanOliver: изначально у меня было такое отражение, потому что я неправильно использовал unsigned long int везде (хорошо с gcc, std::size_t это unsigned long int). И теперь у меня проблема с совместимостью при переносе на Windows с компиляторами Intel, где std::size_t равно unsigned long long int. :-/   -  person Caduchon    schedule 18.07.2017


Ответы (2)


необязательно верно, что std::vector<Foo>::size_type совпадает с std::size_t. Это верно даже для C++11.

Но лично я использую std::size_t для индекса std::vector независимо от типа.

Вы всегда можете использовать статическое утверждение, если чувствуете себя особенно усердно. Очевидно, что static_assert является более поздним дополнением, чем то, что есть в C++98, но в этом стандарте вы могли бы использовать что-то вроде

static char wrong_size_1[1 + sizeof(std::size_t) - sizeof(std::vector<Foo>::size_type)];

static char wrong_size_2[1 - sizeof(std::size_t) + sizeof(std::vector<Foo>::size_type)];

что может привести к сбоям во время компиляции, если типы типов имеют разный размер.

person Bathsheba    schedule 18.07.2017
comment
На самом деле, я уже использую статические утверждения с повышением. Хорошая идея ! - person Caduchon; 18.07.2017
comment
Ух ты. Boost по-прежнему поддерживает C++98! Знаешь, это хорошие яйца. - person Bathsheba; 18.07.2017
comment
Я использую boost 1.57 с GCC 4.4.7 без каких-либо (известных) проблем. ;-) - person Caduchon; 18.07.2017

могу ли я быть уверен, что каждая реализация каждого контейнера в пространстве имен std использует std::size_t как size_type?

Нет, ты не можешь. Однако на практике вы можете быть уверены, что std::size_t достаточно велик для вектора или любого другого контейнера, основанного на одном массиве, потому что

size_t может хранить максимальный размер теоретически возможного объекта любого типа (включая массив).

person eerorika    schedule 18.07.2017
comment
Максимальный размер объекта вполне может быть намного больше максимального size_type вектора. Диапазон для std::vector<>::type составляет только от 0 до numeric_limits<size_t>::max() / sizeof(T), когда T содержится в векторе. Беспокоит возможное сужающее преобразование, я бы сказал. - person StoryTeller - Unslander Monica; 18.07.2017
comment
@StoryTeller Я бы беспокоился, если бы ваше целое число было слишком маленьким для индексации объектов вектора. std::size_t по крайней мере настолько велик, насколько это необходимо, поэтому он может представлять любой индекс. В худшем случае он тратит впустую крошечный бит памяти. - person eerorika; 18.07.2017
comment
Если он слишком мал, у вас будут недоступные элементы. Если он слишком велик, вы зацикливаетесь и, возможно, изменяете элементы в неправильных местах. Я думаю, что одну ошибку легче поймать, чем другую. Сужение конверсий — это больше, чем зло. - person StoryTeller - Unslander Monica; 18.07.2017
comment
@StoryTeller, где вы берете это значение, которое переносится? Поскольку он больше, чем помещается в size_type, он никак не может быть допустимым индексом, и поэтому вы не сможете получить элемент. Использование size_type не упростит устранение ошибки, оно просто перенесет точку переноса на другой фрагмент кода. - person eerorika; 18.07.2017
comment
Ни в коем случае это не будет действительным индексом. За исключением того, что C++ с радостью выполнит неявное сужающее преобразование. Что для целых чисел без знака хорошо определено как модуль 2 в некоторой степени. Отсюда и упаковка. - person StoryTeller - Unslander Monica; 18.07.2017