Должен ли я использовать 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]

Другие вопросы по тегам