Какой тип следует использовать для разницы итераторов, чтобы исключить предупреждения о «возможной потере данных»? - PullRequest
4 голосов
/ 15 октября 2010

Мне нужно общее правило для предупреждений в режиме x64.Какой способ лучше?

Рассмотрим следующие строки кода:

const int N = std::max_element(cont.begin(), cont.end()) - cont.begin();

или

const int ARR_SIZE = 1024;
char arr[ARR_SIZE];
//...
const int N = std::max_element(arr, arr + ARR_SIZE) - arr;

Это мой обычный код.У меня нет проблем с x86.

Но если я запускаю компилятор в режиме x64, у меня появляется несколько предупреждений:

conversion from 'std::_Array_iterator<_Ty,_Size>::difference_type' to 'int', possible loss of data
conversion from '__int64' to 'int', possible loss of data

Я хочу решить эти проблемы по общему правилу.Какой способ лучше?

  1. Создание static_cast:

    const int N = static_cast<int>(
         std::max_element(cont.begin(), cont.end()) - cont.begin()  );
    

    Я думаю, что это не универсальное.И слишком много букв.

  2. Заменить тип вывода на ptrdiff_t:

    const ptrdiff_t N = std::max_element(cont.begin(), cont.end()) - cont.begin();
    

    Что мне делать с этим неизвестным типом ptrdiff_t?Тогда я получу еще дюжину предупреждений.Я хочу сделать много операций с N: сохранить, сложение, умножение, циклы и т. Д. Важно: но что, если std::_Array_iterator<_Ty,_Size>::difference_type и ptrdiff_t - это разные типы? Заменить тип вывода на std::_Array_iterator<_Ty,_Size>::difference_type:

    //h-file
    struct S {
        type mymember; // What is the type?
    };
    
    
    //cpp-file
    typedef std::vector<int> cont_t;
    const cont_t::difference_type N = std::max_element(cont.begin(), cont.end()) - cont.begin();
    // Save N
    S mystruct;
    mystruct.mymember = N; // What type of mystruct.mymember?
    

    Как сохранить N?Какой тип mystruct.mymember?Я не знаю этого в h-файле.

  3. Ваше решение.

Ответы [ 6 ]

3 голосов
/ 15 октября 2010

"а что если std::_Array_iterator<_Ty,_Size>::difference_type и ptrdiff_t - это разные типы?"Не используйте такой компилятор.Кроме того, есть вероятность, что это не может быть формально другим.Например, это относится к vector, использующему стандартный распределитель по умолчанию, поскольку именно здесь он выбирает свои typedefs, но поскольку формальная гарантия не имеет значения (хе-хе, на самом деле это не так), я не собираюсь смотретьэто в черновике C ++ 0x.

Итак, используйте ptrdiff_t.

Но может быть хорошей идеей добавить несколько typedef, например

typedef ptrdiff_t Size;
typedef ptrdiff_t Index;

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

Эти typedefs естественным образом сопровождаются пользовательскими автономными функциями countOf, startOf и endOf, позволяющими обрабатывать необработанные массивы иКонтейнеры стандартной библиотеки точно таким же образом.

Когда вы видите имя Index, становится немного яснее, что это индекс, который не может быть естественным образом извлечен из Index или Sizeмножество типов практически не зависимо от того, что вы делаете.Например, добавьте что-нибудь к этому, это все еще Index.Так что в основном не будет «еще дюжины предупреждений».

Но в некоторых редких случаях вам нужно будет перейти от Index до int, скажем.В и в тех редких случаях просто сделайте static_cast, чтобы закрыть компилятор и прояснить свои намерения.Или даже пользовательская static_cast -подобная narrowTo операция для выразительности ...

Приветствия & hth.,

1 голос
/ 15 октября 2010

Я бы использовал std::ptrdiff_t.

Я не могу придумать разумную реализацию, где std::vector<T>::iterator::difference_type не может быть назначено на std::ptrdiff_t.Они почти наверняка будут одинаковыми.Если они не совпадают, difference_type должен быть меньше, чем ptrdiff_t.

Кроме того, ptrdiff_t является типом со знаком, поэтому, если весь ваш код предназначен для работы с ints, вам будет лучше, чем если бы вы попытались использовать тип без знака, например std::vector<int>::size_type.

1 голос
/ 15 октября 2010

Чтобы сохранить результат max_element () - cont.begin (), вы должны использовать

struct Foo { std::vector<int>::difference_type n; };

или

template<typename T> struct Foo { std::vector<T>::difference_type n; };

или

template<T> struct Foo { T n; };

Поскольку diff_type - это diff_type, и когда вы приводите его к типу int, вы получаете неопределенное поведение.

Вы можете использовать & * c.begin () для преобразования итератора в указатель и использовать ptrdiff_t для различия этих указателей.

0 голосов
/ 15 октября 2010

Использование std::vector<int>::size_type:

  • Гарантируется, что будет представлено любое неотрицательное значение difference_type
  • Это то, что принимают все операции индексации
  • Если cont не пусто, std::max_element(cont.begin(), cont.end()) - cont.begin(); не будет принимать отрицательное значение.Если оно пустое, то вам все равно не следует выполнять эту обработку.

Что мне делать с этим «неизвестным» типом?Тогда я получу еще дюжину предупреждений.Я хочу сделать много операций с N: сохранить, сложение, умножение, циклы и т. Д.

Вы не получите никаких предупреждений, если будете использовать тип последовательно и ограничивать использование тем, что вам действительно нужноЭто.N - указатель на вектор;это все, для чего это хорошо.Любая значимая операция, которую вы выполняете с этим, приведет к другому возможному индексу в вектор.

0 голосов
/ 15 октября 2010

Мое решение состоит в том, чтобы использовать тип, который известен как достаточно большой, основываясь на знаниях предметной области, которые у меня есть, но которые могут быть недоступны для компилятора.Если затем компилятор жалуется на возможную потерю данных, я добавляю приведение (которое гарантированно безопасно, потому что я заранее знаю, что целевой тип должен быть достаточно большим).

0 голосов
/ 15 октября 2010

В visual-studio-2010 вы можете написать:

const auto N = std::max_element( cont.begin(), cont.end() ) - cont.begin();
...