Обновить
16K+
4,8
Оценка работодателя
68,57
Рейтинг
240
Подписчики

На днях в офисе я столкнулась с коллегами из направления системного программирования в «Криптоните». Они пишут на С++ — а ошибки на этом языке у нас ещё не было!

Поэтому я попросила их придумать код с ошибкой специально для Хабра — и вот что получилось!

Итак, есть ли в этом коде проблема кроме narrowing conversion? Ждём ваши варианты в комментариях.

#include <cstdint>
#include <vector>

struct Type
{
    Type(uint16_t, uint32_t = {}) 
    {}
};

int main()
{
    std::vector<Type> vector;
    std::uint32_t object_id{};

    // Есть предупреждение о narrowing conversion
    vector.insert(vector.begin(), {0, object_id}); 

    // Нет narrowing conversion
    vector.push_back({0, object_id}); 

    // Нет narrowing conversion
    vector.insert(vector.begin(), Type{0, object_id}); 
}

АККУРАТНО, ДАЛЬШЕ СПОЙЛЕР!

Проблема в том, что в строке

 vector.insert(vector.begin(), {0, object_id});

в вектор вставляется 2 элемента типа Type, а не один, как ожидает программист.

Причина в том, что метод insert у вектора имеет перегрузку (номер 5), которая вторым параметром принимает std::initializer_list. А компилятор, видя фигурные скобки в коде, в первую очередь пытается создать объект такого типа.

И тут ему это удается, потому что у конструктора Type второй параметр имеет значение по умолчанию, следовательно, Type умеет создаваться, если в конструктор передали только один аргумент. В итоге компилятор успешно создает std::initializer_list с двумя элементами типа Type.

Так как создание std::initializer_list выполняется с использованием uniform initialization, то компилятор следит за корректностью преобразований. В примере объект типа std::uint32_t передается в конструктор Type, который принимает первым параметром std::uint16_t. То есть, возникает риск потери точности (32 бита не могут поместиться в 16 бит).

Об этом компилятор и предупреждает. Вот упрощенный пример, где видим то же самое предупреждение.

Может возникнуть вопрос, почему создание Type от 0 не вызывает предупреждение, ведь 0 - это int, а он, скорее всего 32 бита и тоже не помещается в 16 бит. Но тут литерал. Компилятор видит, что 0 вмещается в 16 бит и не предупреждает. Но если поместить int в переменную, то также возникает предупреждение.

Теги:
Всего голосов 3: ↑3 и ↓0+3
Комментарии0

«Яндекс Go» предложит пассажирам ждать такси 30–40 минут ради скидки

Пассажиры «Яндекс Go» смогут сэкономить на поездке в часы, когда такси заказывают особенно много людей. В такие моменты сервис предложит опцию «Позже»: машина приедет не сразу, зато поездка будет стоить меньше. Скидку даст «Яндекс Go» за свой счёт, она не уменьшит доход водителей.

«Яндекс Go» предложит пассажирам ждать такси 30–40 минут ради скидки

Публикации

Информация

Сайт
kryptonite.ru
Дата регистрации
Дата основания
Численность
501–1 000 человек
Местоположение
Россия