Кажется безопасным преобразовать результат моей векторной функции size() в unsigned int. Но как я могу сказать наверняка? В моей документации не совсем ясно, как определяется size_type.
Что, если ему нужно передать размер контейнера какому-то существующему коду, который использует, скажем, беззнаковое целое число?
Тогда ему не повезло, потому что в 64-битной системе vector :: size_type вполне может быть больше, чем unsigned int.
@JF: Тогда просто оставьте предупреждение или исправьте код, который вы вызываете. Не приводите тип, чтобы удалить предупреждение, это просто нарушит код, когда вы перейдете в новую систему, где ваши предположения не работают.
Или удалите предупреждение, но добавьте утверждение (желательно во время компиляции), которое срабатывает, когда предположение не выполняется. В GCC, например, есть старый трюк с объявлением char [sizeof (unsigned int) - sizeof (size_type)], который взрывается, когда разница отрицательная.





По стандарту ты не можешь быть уверен. Точный тип зависит от вашей машины. Тем не менее, вы можете посмотреть определение в реализациях заголовка вашего компилятора.
Я попытался заглянуть в заголовки. Пройдя целый лабиринт общих определений, я зашел в тупик в файле под названием xmemory, где упоминается тип size_t. Согласно моей IDE size_t нигде не определено!
Ага - чтение заголовков библиотек (особенно основанных на шаблонах) может быть настоящей головной болью.
По крайней мере, в gcc заголовок, который фактически определяет size_t (stddef.h), похоронен где-то еще, далеко от обычных include (/usr/lib/gcc/.../include вместо / usr / include).
size_t - это стандартное определение типа C. Посмотрите cstddef, который, вероятно, приведет вас к stddef.h (cplusplus.com/reference/clibrary/cstring/size_t.html). На самом деле, как и NULL, большинство знакомых мне программистов не включают cstddef перед использованием size_t. Честно говоря, size_t, вероятно, будет целым числом без знака.
В общем, вы должны использовать size_t там, где у вас может возникнуть соблазн использовать unsigned int. Для обоих типов вы не можете быть уверены, сколько битов они содержат, но в случае size_t вы должны быть уверены, что может достаточно велик, чтобы измерить размер вещей в памяти.
Вопрос в том, зачем вам это нужно?
@ Мартин: Зачем тебе что? Определить, может ли int содержать size_type? Если это то, о чем вы спрашиваете, то, как JF несколько раз упоминал, это может быть из-за того, что вы передаете его в API или что-то, что вы не контролируете, что хочет int.
Пока вы уверены, что unsigned int в вашей системе будет достаточно большим, чтобы вместить количество элементов, которые у вас будут в векторе, вы должны быть в безопасности ;-)
Но это делает код не порталом. Все дело в том, чтобы писать хороший код.
"до тех пор, пока .. unsigned int .. будет достаточно большим". Это то, что Томми пытается выяснить. Это не ответ.
Точно! Всякий раз, когда вы выполняете приведение, вы переопределяете систему типов, поэтому вам нужно знать, что вы делаете.
@Aaron: Я думаю, вы неправильно поняли ответ JF. Он указывает, что это безопасно, если фактический размер вектора во время выполнения не превышает UINT_MAX. Это более слабое условие, чем то, что ширина size_type не больше ширины unsigned int.
Я не могу себе представить, что это было бы небезопасно в 32-битной системе, но 64-битная версия может быть проблемой (поскольку ints остаются 32-битными). На всякий случай, почему бы просто не объявить вашу переменную vector <MyType> :: size_type вместо unsigned int?
Это то, что я сделал, но мне все еще любопытно, как искать информацию в STL.
@Tommy: У тебя уже есть вся необходимая информация. Приведение небезопасно, вместо этого следует использовать "vector <MyType> :: size_type". или size_t. Если вы только любопытный, что это такое, спросите компилятор: cout << typeid (size_t) .name () << "\ n"; // если вы спросите вежливо, он может вам сказать.
Я не уверен, насколько хорошо это будет работать, потому что я просто мысленно думаю, но утверждение времени компиляции (например, BOOST_STATIC_ASSERT() или см. Способы выполнения выражений ASSERT во время сборки в C) может помочь. Что-то типа:
BOOST_STATIC_ASSERT( sizeof( unsigned int) >= sizeof( size_type));
Но почему. Предположение, что здесь работает тип, не поможет при публикации кода.
Может быть, я что-то неправильно понимаю - если компилятор может проверить, что любой тип, в который вы хотите, чтобы размер входил, по крайней мере, такой же большой, как тип, который вы получаете из size (), разве это не отвечает на вопрос OP? Даже если это не решит проблему автоматически
Обратите внимание, что я предположил, что OP хочет преобразовать size_type в int, потому что он передает результат size () функции / методу / структуре / тому, что хочет int и не находится под его контролем.
Всегда должно быть безопасно преобразовать его в size_t. unsigned int недостаточно в большинстве 64-битных систем, и даже unsigned long недостаточно в Windows (которая использует модель LLP64 вместо модели LP64, которую используют большинство Unix-подобных систем).
Не предполагайте тип размера контейнера (или что-то еще, введенное внутри).
Лучшее решение на данный момент - использовать:
std::vector<T>::size_type
Где Т твой тип. Например:
std::vector<std::string>::size_type i ;
std::vector<int>::size_type j ;
std::vector<std::vector<double> >::size_type k ;
(Использование typedef может помочь облегчить чтение)
То же самое касается итераторов и всех других типов "внутри" контейнеров STL.
Когда компилятор сможет найти тип переменной, вы сможете использовать ключевое слово auto. Например:
void doSomething(const std::vector<double> & p_aData)
{
std::vector<double>::size_type i = p_aData.size() ; // Old/Current way
auto j = p_aData.size() ; // New C++0x way, definition
decltype(p_aData.size()) k; // New C++0x way, declaration
}
What if he needs to pass the size of the container to some existing code that uses, say, an unsigned int? – JF
Это проблема, типичная для использования STL: вы не можете сделать это без некоторой работы.
Первое решение - разработать код, чтобы всегда использовать тип STL. Например:
typedef std::vector<int>::size_type VIntSize ;
VIntSize getIndexOfSomeItem(const std::vector<int> p_aInt)
{
return /* the found value, or some kind of std::npos */
}
Второй - выполнить преобразование самостоятельно, используя либо static_cast, используя функцию, которая будет утверждать, если значение выходит за пределы целевого типа (иногда я вижу код, использующий «char», потому что «знаете, индекс никогда не выйдет за пределы 256» [цитирую из объем памяти]).
Я считаю, что это сам по себе полный вопрос.
Что, если ему нужно передать размер контейнера какому-то существующему коду, который использует, скажем, беззнаковое целое число?
На практике (и при использовании стандартных контейнеров) size_type можно заменить на size_t. Вот обсуждение этого: velocityreviews.com/forums/t281965-sizet-and-sizetype.html
В стандарте C++ указано только, что size_t находится в <cstddef>, что помещает идентификаторы в <stddef.h>. Моя копия Харбисон и Стил помещает минимальные и максимальные значения для size_t в <stdint.h>. Это должно дать вам представление о том, насколько большой должна быть переменная получателя для вашей платформы.
Лучше всего придерживаться целочисленных типов, которые достаточно велики, чтобы удерживать указатель на вашей платформе. В C99 это будут intptr_t и uintptr_t, также официально расположенные в <stdint.h>.
Почему вы хотите передать результат чему-то еще? Тот факт, что вы получаете несоответствие типов, указывает на то, что в вашем коде что-то не так, что необходимо (или должно) быть исправлено (вот почему C++ имеет СИЛЬНУЮ типизацию). Не пытайтесь свернуть систему типов.