Должен ли я использовать static_cast в присваиваниях и операторах возврата и почему?
Вот два очень похожих фрагмента:
vector<int> a;
int n = static_cast<int>(a.size());
// ---------
int f(const vector<int>& a) {
return static_cast<int>(a.size());
}
Здесь я явно приведу значение типа size_t
печатать int
, Если я опущу static_cast
то же самое действие применяется неявно.
К какому виду относится этот скрытый актерский состав? Безопасно ли опускать static_cast
в явных присваиваниях и операторах возврата?
3 ответа
Этот актерский состав не настолько безопасен, на самом деле ценность n
может быть определена реализацией (стандарт C++ [conv.integral]):
Если тип назначения подписан, значение остается неизменным, если оно может быть представлено в типе назначения, в противном случае значение определяется реализацией.
Если вы включите все предупреждения и не используете static_cast, ваш компилятор может сообщить вам о сужающемся преобразовании. Если вы используете static_cast
, вы сообщите читателю своего кода, что вы точно знаете, что a.size() <= std::numeric_limits<int>::max()
или что вы знаете, что собирается делать ваша реализация, если такое условие не выполняется.
(обратите внимание, что возможно, что предыдущее сравнение также вызывает преобразование, определяемое реализацией, если std::size_t меньше, чем int, стандарт C++ это позволяет)
Это было бы интегральным преобразованием. И при этом сужение.
Для инициализации переменной, если вам нужен конкретный тип, хорошим подходом будет сделать то, что предлагает Херб Саттер в своей статье"Почти всегда авто":
auto n = int{a.size()};
По возможности используйте инициализацию списка. Это предотвратит сужение конверсий, и ваш компилятор пометит вам использовать явное приведение при необходимости (например, в случае выше).
Необходимость литья определяется обязательно конверсией. Таким образом, реальный вопрос здесь должен быть "зачем мне возвращать / хранить int
вместо vector<int>::size_type
?"Если вашей программной логике действительно не требуется такое преобразование, то вообще не выполняйте ее. Если вашей программной логике требуется такое преобразование (например, вам нужно передать это значение в вызов сторонней функции, которая принимает int
) тогда тебе стоит использовать static_cast
, Опуская static_cast
в этом случае будет признаком непреднамеренного сужения преобразования и вызовет соответствующие предупреждения компилятора, такие как warning C4267: 'initializing': conversion from 'size_t' to 'int', possible loss of data
или же warning: conversion to 'int' from 'std::vector<int>::size_type {aka long unsigned int}' may alter its value [-Wconversion]