Я работаю с большим количеством вычислительного кода, написанного на C ++, имея в виду высокую производительность и небольшие накладные расходы на память. Он часто использует контейнеры STL (в основном vector
) и перебирает эти контейнеры почти в каждой отдельной функции.
Повторяющийся код выглядит так:
for (int i = 0; i < things.size(); ++i)
{
// ...
}
но выдает предупреждение о несоответствии со знаком / без знака (C4018 в Visual Studio).
Замена int
на какой-либо unsigned
тип - проблема, потому что мы часто используем прагмы OpenMP, и для этого требуется счетчик int
.
Я собираюсь подавить (сотни) предупреждений, но боюсь, что упустил изящное решение проблемы.
Об итераторах . Я считаю, что итераторы хороши, когда применяются в соответствующих местах. Код, с которым я работаю, никогда не изменит контейнеры с произвольным доступом list
или что-то в этом роде (поэтому итерация int i
уже не зависит от контейнера) и всегда будет нуждаться в текущем индексе. И весь дополнительный код, который вам нужно ввести (сам итератор и индекс), просто усложняет ситуацию и скрывает простоту основного кода.
источник
int
.int
аstd::vector<T>::size_type
также могут быть разными по размеру и подписи. Например, в системе LLP64 (например, 64-битной Windows),sizeof(int) == 4
ноsizeof(std::vector<T>::size_type) == 8
.Ответы:
Это все в твоем
things.size()
вкусе. Это не такint
, ноsize_t
(он существует в C ++, а не в C), который соответствует какому-то «обычному» беззнаковому типу, то естьunsigned int
для x86_32.Оператор «меньше» (<) не может применяться к двум операндам разного знака. Таких кодов операций просто нет, и стандарт не указывает, может ли компилятор выполнять неявное преобразование знака. Таким образом, он просто обрабатывает подписанное число как неподписанное и выдает это предупреждение.
Правильнее было бы написать так
for (size_t i = 0; i < things.size(); ++i) { /**/ }
или даже быстрее
for (size_t i = 0, ilen = things.size(); i < ilen; ++i) { /**/ }
источник
size_t
. Это такstd::vector< THING >::size_type
.std::size_t
иstd::vector<T>::size_type
.В идеале я бы использовал такую конструкцию:
for (std::vector<your_type>::const_iterator i = things.begin(); i != things.end(); ++i) { // if you ever need the distance, you may call std::distance // it won't cause any overhead because the compiler will likely optimize the call size_t distance = std::distance(things.begin(), i); }
У этого есть преимущество в том, что ваш код внезапно становится независимым от контейнера.
Что касается вашей проблемы, если какая-то используемая вами библиотека требует, чтобы вы использовали ее
int
там, гдеunsigned int
она лучше всего подходит, их API беспорядочный. В любом случае, если вы уверены, чтоint
они всегда положительные, вы можете просто сделать:int int_distance = static_cast<int>(distance);
Что четко укажет компилятору ваше намерение: он больше не будет вызывать у вас предупреждений.
источник
static_cast<int>(things.size())
быть, решения могут быть, если других нет.#pragma warning(push) #pragma warning(disable: 4018) /* ... function */ #pragma warning(pop)
) вместо использования ненужного приведения. (Броски скрывают допустимые ошибки, хорошо?;))Если вы не можете / не будете использовать итераторы , и если вы не можете / не использовать
std::size_t
для индекса петли, сделать.size()
дляint
функции преобразования , что документы Допущения и делают преобразование явно , чтобы отключить предупреждение компилятора.#include <cassert> #include <cstddef> #include <limits> // When using int loop indexes, use size_as_int(container) instead of // container.size() in order to document the inherent assumption that the size // of the container can be represented by an int. template <typename ContainerType> /* constexpr */ int size_as_int(const ContainerType &c) { const auto size = c.size(); // if no auto, use `typename ContainerType::size_type` assert(size <= static_cast<std::size_t>(std::numeric_limits<int>::max())); return static_cast<int>(size); }
Затем вы пишете свои циклы так:
for (int i = 0; i < size_as_int(things); ++i) { ... }
Создание экземпляра этого шаблона функции почти наверняка будет встроенным. В отладочных сборках предположение будет проверено. В сборках релизов этого не будет, и код будет работать так же быстро, как если бы вы вызывали size () напрямую. Ни одна из версий не выдаст предупреждение компилятора, и это лишь небольшая модификация идиоматического цикла.
Если вы хотите отловить ошибки предположений и в выпускной версии, вы можете заменить утверждение на оператор if, который выдает что-то вроде
std::out_of_range("container size exceeds range of int")
.Обратите внимание, что это решает как сравнение со знаком / без знака, так и потенциальную проблему
sizeof(int)
! =sizeof(Container::size_type)
. Вы можете оставить все предупреждения включенными и использовать их для поиска реальных ошибок в других частях вашего кода.источник
Вы можете использовать:
Например:
// simple class who output his value class ConsoleOutput { public: ConsoleOutput(int value):m_value(value) { } int Value() const { return m_value; } private: int m_value; }; // functional object class Predicat { public: void operator()(ConsoleOutput const& item) { std::cout << item.Value() << std::endl; } }; void main() { // fill list std::vector<ConsoleOutput> list; list.push_back(ConsoleOutput(1)); list.push_back(ConsoleOutput(8)); // 1) using size_t for (size_t i = 0; i < list.size(); ++i) { std::cout << list.at(i).Value() << std::endl; } // 2) iterators + distance, for std::distance only non const iterators std::vector<ConsoleOutput>::iterator itDistance = list.begin(), endDistance = list.end(); for ( ; itDistance != endDistance; ++itDistance) { // int or size_t int const position = static_cast<int>(std::distance(list.begin(), itDistance)); std::cout << list.at(position).Value() << std::endl; } // 3) iterators std::vector<ConsoleOutput>::const_iterator it = list.begin(), end = list.end(); for ( ; it != end; ++it) { std::cout << (*it).Value() << std::endl; } // 4) functional objects std::for_each(list.begin(), list.end(), Predicat()); }
источник
Я также могу предложить следующее решение для C ++ 11.
for (auto p = 0U; p < sys.size(); p++) { }
(C ++ недостаточно умен для auto p = 0, поэтому я должен поставить p = 0U ....)
источник
for (auto thing : vector_of_things)
если вам действительно не нужен index.size()
возвращается тип, больший, чем unsigned int, что очень часто.Я дам вам лучшую идею
for(decltype(things.size()) i = 0; i < things.size(); i++){ //... }
decltype
являетсяИтак, он выводит тип
things.size()
иi
будет таким же видом, как иthings.size()
. Итак,i < things.size()
будет выполнено без предупрежденияисточник
У меня была аналогичная проблема. Использование size_t не помогло. Я попробовал другой, который у меня работал. (как показано ниже)
for(int i = things.size()-1;i>=0;i--) { //... }
источник
Я бы просто сделал
int pnSize = primeNumber.size(); for (int i = 0; i < pnSize; i++) cout << primeNumber[i] << ' ';
источник