VC++: инициализация объекта выражением с int/uint
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 22.03.22 18:03
Оценка:
Есть у меня мелкий класс, хранящий 64-разрядные значения. Если в классе определить только самые общие конструкторы с параметрами int64 и uint64, то объект невозможно инициализировать просто числовым литералом вроде "-100", или выражением типа int/uint — комплилятор (MSVC) отказывается автоматически преобразовывать тип, требуя явного преобразования.

Если же добавить конструкторы с параметрами int, uint, long, ulong, пометив их explicit, то все прекрасно, пока я не пытаюсь инициализировать объект выражением вроде "-10 * n", где n — unsigned int. По правилам языка, такое выражение приводится к unsigned int, для него вызывается соответствующий конструктор, который выполняет беззнаковое расширение, хотя по смыслу требуется знаковое. Постоянно держать в уме такие мелочи напряжно, и я периодически об этом нюансе забываю. У компилятора предупреждения на этот счет не предусмотрено.

Можно ли как-то обезопасить себя от таких ошибок средствами языка? И, кстати, более другие компиляторы умеют выдавать предупреждение в такой ситуации?
Re: VC++: инициализация объекта выражением с int/uint
От: Maniacal Россия  
Дата: 23.03.22 06:01
Оценка: -3 :)
Здравствуйте, Евгений Музыченко, Вы писали:

ЕМ>Если же добавить конструкторы с параметрами int, uint, long, ulong, пометив их explicit, то все прекрасно, пока я не пытаюсь инициализировать объект выражением вроде "-10 * n", где n — unsigned int. По правилам языка, такое выражение приводится к unsigned int, для него вызывается соответствующий конструктор, который выполняет беззнаковое расширение, хотя по смыслу требуется знаковое.


Не факт. Если, например, попытаться разделить int на double, то результатом будет не double, а int. Нужно предварительное явное преобразование int в double.
Re: VC++: инициализация объекта выражением с int/uint
От: T4r4sB Россия  
Дата: 23.03.22 06:10
Оценка: +1
Здравствуйте, Евгений Музыченко, Вы писали:

ЕМ>Можно ли как-то обезопасить себя от таких ошибок средствами языка?


Да. Это выкинуть все дополнительные конструкторы
Re[2]: VC++: инициализация объекта выражением с int/uint
От: Doom100500 Израиль  
Дата: 23.03.22 06:52
Оценка:
Здравствуйте, Maniacal, Вы писали:

M>Здравствуйте, Евгений Музыченко, Вы писали:


M>Не факт. Если, например, попытаться разделить int на double, то результатом будет не double, а int. Нужно предварительное явное преобразование int в double.


  Чего?
Спасибо за внимание
Re[3]: VC++: инициализация объекта выражением с int/uint
От: Maniacal Россия  
Дата: 23.03.22 07:25
Оценка:
Здравствуйте, Doom100500, Вы писали:

D>Здравствуйте, Maniacal, Вы писали:


M>>Здравствуйте, Евгений Музыченко, Вы писали:


M>>Не факт. Если, например, попытаться разделить int на double, то результатом будет не double, а int. Нужно предварительное явное преобразование int в double.


D>
  Чего?
D>Image: Screenshot 2022-03-23 084910.png


Были проблемы пару раз. Но, наверное, подзабылось. Это int на int если поделить результат целочисленным будет и нужно первый int в double преобразовать сначала.
Re[2]: VC++: инициализация объекта выражением с int/uint
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 23.03.22 08:24
Оценка:
Здравствуйте, Maniacal, Вы писали:

ЕМ>>Нужно предварительное явное преобразование int в double.


В паре double/int как раз не нужно — общим всегда выбирается более "широкий" тип. Но в паре int/uint беда в том, что выражение вроде "-10 * n" интуитивно ожидается знаковым, а при беззнаковом n результат получается беззнаковым. Поэтому нужно предупреждение, а MSVC его не дает. Кто-нибудь из других компиляторов дает?
Re[2]: VC++: инициализация объекта выражением с int/uint
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 23.03.22 08:26
Оценка:
Здравствуйте, T4r4sB, Вы писали:

TB>выкинуть все дополнительные конструкторы


Да, я уже сообразил, что будет достаточно INT64. Остальные конструкторы добавлял по какой-то другой причине, а когда в целом заработало — так и оставил.

Но проблемы с преобразованием выражений вроде "-10 * n" с беззнаковым n это не снимает.
Re: VC++: инициализация объекта выражением с int/uint
От: SaZ  
Дата: 23.03.22 09:49
Оценка:
Здравствуйте, Евгений Музыченко, Вы писали:

ЕМ>Есть у меня мелкий класс, хранящий 64-разрядные значения. Если в классе определить только самые общие конструкторы с параметрами int64 и uint64, то объект невозможно инициализировать просто числовым литералом вроде "-100", или выражением типа int/uint — комплилятор (MSVC) отказывается автоматически преобразовывать тип, требуя явного преобразования.


ЕМ>Если же добавить конструкторы с параметрами int, uint, long, ulong, пометив их explicit, то все прекрасно, пока я не пытаюсь инициализировать объект выражением вроде "-10 * n", где n — unsigned int. По правилам языка, такое выражение приводится к unsigned int, для него вызывается соответствующий конструктор, который выполняет беззнаковое расширение, хотя по смыслу требуется знаковое. Постоянно держать в уме такие мелочи напряжно, и я периодически об этом нюансе забываю. У компилятора предупреждения на этот счет не предусмотрено.


ЕМ>Можно ли как-то обезопасить себя от таких ошибок средствами языка? И, кстати, более другие компиляторы умеют выдавать предупреждение в такой ситуации?


На ум приходят только шаблонные конструкторы с соответствующими статик ассертами.
Re[2]: VC++: инициализация объекта выражением с int/uint
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 23.03.22 10:11
Оценка: 1 (1)
Здравствуйте, SaZ, Вы писали:

SaZ>На ум приходят только шаблонные конструкторы с соответствующими статик ассертами.


Как здесь могут помочь шаблонные конструкторы? Приведение значения выражения вида "-10 * n" к беззнаковому типу происходит еще на стадии обработки самого выражения, и только потом начинается поиск подходящего конструктора.
Re[3]: VC++: инициализация объекта выражением с int/uint
От: reversecode google
Дата: 24.03.22 20:24
Оценка: 3 (1)
sfinae
Re: VC++: инициализация объекта выражением с int/uint
От: kov_serg Россия  
Дата: 24.03.22 21:48
Оценка:
Здравствуйте, Евгений Музыченко, Вы писали:


ЕМ>...пока я не пытаюсь инициализировать объект выражением вроде "-10 * n", где n — unsigned int.

Просто не делайте так.

ЕМ>Можно ли как-то обезопасить себя от таких ошибок средствами языка?

Пишите явно мелкий_класс(-10)*мелкий_класс(n)
Более того в новых редакциях есть такая хрень
Re[2]: VC++: инициализация объекта выражением с int/uint
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 25.03.22 08:50
Оценка:
Здравствуйте, kov_serg, Вы писали:

_>Просто не делайте так.


Это равнозначно совету никогда и ни за что не допускать в речи слов-паразитов вроде "ну" или "это". Если у Вас получается ни разу так не сделать за несколько лет — искренне завидую.

_>Пишите явно мелкий_класс(-10)*мелкий_класс(n)


Не понял. Во-первых, это уродливо. Во-вторых, такой класс вовсе не обязан возвращать в точности то значение, которым был инициализирован.

_>Более того в новых редакциях есть такая хрень


Снова не то. Лучше всего здесь подойдет обычное предупреждение компилятора — не понимаю, почему даже сейчас его нигде нет.
Re[3]: VC++: инициализация объекта выражением с int/uint
От: kov_serg Россия  
Дата: 25.03.22 10:24
Оценка:
Здравствуйте, Евгений Музыченко, Вы писали:

_>>Пишите явно мелкий_класс(-10)*мелкий_класс(n)


ЕМ>Не понял. Во-первых, это уродливо. Во-вторых, такой класс вовсе не обязан возвращать в точности то значение, которым был инициализирован.

Если вы так переживаете что можете инициализировать не тем что ожидали. Введите явные ограничения. Но вот если вам эти ограничения не нравятся, это уже не ко мне.

_>>Более того в новых редакциях есть такая хрень

ЕМ>Снова не то. Лучше всего здесь подойдет обычное предупреждение компилятора — не понимаю, почему даже сейчас его нигде нет.
Потому что это язык в котором куча UB о который он предпочитает не сообщать, сваливая всю ответственность на программиста
Re[4]: VC++: инициализация объекта выражением с int/uint
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 25.03.22 11:16
Оценка:
Здравствуйте, kov_serg, Вы писали:

_>Если вы так переживаете что можете инициализировать не тем что ожидали. Введите явные ограничения.


По-прежнему не понимаю, как могли бы выглядеть ограничения. Можно примеров? В примере с двумя временными объектами я вижу не ограничения, а костыль, о котором также придется непрерывно помнить. Чем это лучше?

_>Потому что это язык в котором куча UB о который он предпочитает не сообщать, сваливая всю ответственность на программиста


"Предпочитает не сообщать" не язык, а конкретные его компиляторы. Вот меня и удивляет, почему нет возможности сообщать о любом возможном UB, и любой возможной неоднозначности, без исключения. Из-за этого процветают статические анализаторы вроде PVS Studio, в которых, по сути, приходится делать свои недокомпиляторы.
Re[5]: VC++: инициализация объекта выражением с int/uint
От: kov_serg Россия  
Дата: 25.03.22 12:01
Оценка: 15 (1)
Здравствуйте, Евгений Музыченко, Вы писали:

ЕМ>По-прежнему не понимаю, как могли бы выглядеть ограничения. Можно примеров? В примере с двумя временными объектами я вижу не ограничения, а костыль, о котором также придется непрерывно помнить. Чем это лучше?

struct A {
  A(unsigned long long x) : x(x) {}
  template<class T> A(T t)=delete;
  unsigned long long x;
};
Re[5]: VC++: инициализация объекта выражением с int/uint
От: ArtDenis Россия  
Дата: 25.03.22 15:12
Оценка:
Здравствуйте, Евгений Музыченко, Вы писали:

ЕМ>Вот меня и удивляет, почему нет возможности сообщать о любом возможном UB, и любой возможной неоднозначности, без исключения. Из-за этого процветают статические анализаторы вроде PVS Studio, в которых, по сути, приходится делать свои недокомпиляторы.


Ну так сторонние статанализаторы никогда не помешают. Если встроенный Microsoft Code Analysis молчит как партизан, то cppcheck даёт корректный варнинг на это дело.

void f(int) {}
void f(unsigned) {}

int main()
{
    int i = -1;
    unsigned u = 10;

    f(i * u);
}

[test.cpp:9]: (warning) Expression 'i' can have a negative value. That is converted to an unsigned value and used in an unsigned calculation.


Заодно ещё что-нибудь найдёшь в коде, о чём не подозревал даже
[ 🎯 Дартс-лига Уфы | 🌙 Программа для сложения астрофото ]
Re[6]: VC++: инициализация объекта выражением с int/uint
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 25.03.22 15:31
Оценка:
Здравствуйте, kov_serg, Вы писали:

_>  A(unsigned long long x) : x(x) {}
_>  template<class T> A(T t)=delete;


О, такое вполне годится, спасибо! Кривовато, но хоть не уродливо.
Re[6]: VC++: инициализация объекта выражением с int/uint
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 25.03.22 15:35
Оценка:
Здравствуйте, ArtDenis, Вы писали:

AD>Ну так сторонние статанализаторы никогда не помешают.


Они были бы вообще не нужны, имейся встроенные средства анализа у каждого серьезного компилятора. Там же, по сути, особо ничего и добавлять не нужно, кроме наборов условий для выдачи предупреждения, которые составляют очень малую часть от всего кода компилятора. А вот разработчикам любого статанализатора приходится, по сути, создавать полноценный компилятор, разве что без кодогенератора.
Re[7]: VC++: инициализация объекта выражением с int/uint
От: ArtDenis Россия  
Дата: 25.03.22 15:45
Оценка:
Здравствуйте, Евгений Музыченко, Вы писали:

AD>>Ну так сторонние статанализаторы никогда не помешают.


ЕМ>Они были бы вообще не нужны, имейся встроенные средства анализа у каждого серьезного компилятора. Там же, по сути, особо ничего и добавлять не нужно, кроме наборов условий для выдачи предупреждения, которые составляют очень малую часть от всего кода компилятора. А вот разработчикам любого статанализатора приходится, по сути, создавать полноценный компилятор, разве что без кодогенератора.


Полностью согласен. Но меня вся эта философия не особо интересует. Я просто пользуюсь статанализаторами потому что они работают и помогают, и особо задумываюсь над тем, что они частично повторяют компиляторы внутри. Кстати, Clang Static Analyzer основан на его же компиляторе и поэтому его авторам не пришлось переизобретать велосипед )
[ 🎯 Дартс-лига Уфы | 🌙 Программа для сложения астрофото ]
Re[8]: VC++: инициализация объекта выражением с int/uint
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 25.03.22 18:38
Оценка:
Здравствуйте, ArtDenis, Вы писали:

AD>Я просто пользуюсь статанализаторами потому что они работают и помогают


Вы ими пользуетесь при каждой отладочной сборке? Я бы предпочел, чтобы этим занимался основной компилятор.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.