Ну вот какого хрена в век, когда лямбды уже не вызывают "это ты выпендрился?"-реакцию на код ревью, когда все самые необходимые смарт-поинтеры уже есть в std, а в boost есть вообще все нужные, до сих пор можно наткнуться на непредсказуемую инициализацию переменных?
int count;
RegQueryValue(count); // забыли проверить возвращаемое значениеfor (int i = 0 ; i < count ; i++) // и приплыли - цикл повторяется непредсказуемое количество раз
Почему не введут инициализацию для всех простых типов?
Для маньяков, которые не желают "платить за то, что не используют", можно же ввести синтаксис для "старой доброй русской рулетки".
Варианты, как это можно сделать:
int i = uninitialized; // "uninitialized" - не спец. значение, а magic, работающий только в инициализаторах, означающий, что мы хотим адреналинаint i = void; // мы даже можем не вводить новый кейворд, если это так важно
[[uninitialized]]
int i; // придумали аттрибуты, значит почему бы не использовать
Здравствуйте, Alexander G, Вы писали:
AG>Почему не введут инициализацию для всех простых типов?
Обратная совместимость + увеличится объём кода.
В силу того что компилятор выдаёт предупреждения по поводу неинициализированных переменных,
никому спец синтаксис для этого не нужен.
AG>Может, это можно протянуть как пропозл?
12/20/2013 12:11 PM, Alexander G пишет:
> Почему не введут инициализацию для всех простых типов?
Потому что тупую голову и кривые руки инструментом не поправишь.
Здравствуйте, Vzhyk, Вы писали:
V>12/20/2013 12:11 PM, Alexander G пишет:
>> Почему не введут инициализацию для всех простых типов? V>Потому что тупую голову и кривые руки инструментом не поправишь.
Здравствуйте, skeptic, Вы писали:
S>Обратная совместимость
С чем? Кто-то рассчитывает прочитать определённый мусор?
S> + увеличится объём кода.
Чтобы пофиксить local static variables, сделав их потокобезопасными, на это пошли.
Вообще, в большинстве случаев переменные явно инициализированы в месте объеявления.
Если чуть позже места объявления — можно соптимизировать.
Если вообще не инициализированы, но использованы — это, скорее всего, та самая ошибка.
S>В силу того что компилятор выдаёт предупреждения по поводу неинициализированных переменных, S>никому спец синтаксис для этого не нужен.
студия спокойно глотает с /W4 и даже /WAll
inline void f(int&) {}
int main()
{
int i;
f(i);
return i;
}
Здравствуйте, Alexander G, Вы писали:
AG>Здравствуйте, skeptic, Вы писали:
S>>Обратная совместимость
AG>С чем? Кто-то рассчитывает прочитать определённый мусор?
Ну, если я тебя правильно понял, то ты хочешь что бы переменную нельзя было объявить без определения, так?
Ну в таком случае у тебя куча уже написанного кода перестанет работать.
S>Ну, если я тебя правильно понял, то ты хочешь что бы переменную нельзя было объявить без определения, так? S>Ну в таком случае у тебя куча уже написанного кода перестанет работать.
Нет, я хочу, чтобы просто
int i;
компилилось как
int i = 0;
а если не нужен этот "= 0", то синтаксис, как выше.
Здравствуйте, Alexander G, Вы писали:
AG>Здравствуйте, skeptic, Вы писали:
S>>Ну, если я тебя правильно понял, то ты хочешь что бы переменную нельзя было объявить без определения, так? S>>Ну в таком случае у тебя куча уже написанного кода перестанет работать.
AG>Нет, я хочу, чтобы просто
AG>
AG>int i;
AG>
AG>компилилось как
AG>
AG>int i = 0;
AG>
AG>а если не нужен этот "= 0", то синтаксис, как выше.
А что такое — "= 0"? и для любого ли типа такой 0 прокатит?
Ну и в конце концов чем отличается такой вот 0 от мусора?
Здравствуйте, Alexander G, Вы писали:
AG>Здравствуйте, skeptic, Вы писали:
S>>Ну и в конце концов чем отличается такой вот 0 от мусора?
AG>Предсказуемостью. Меньше будет проблем которые воспроизводятся только в определённой фазе луны.
Какой предсказуемостью? Как ты узнаешь что 0 это неинициализированная переменная а не кто то присвоил 0?
Здравствуйте, skeptic, Вы писали:
S>Какой предсказуемостью? Как ты узнаешь что 0 это неинициализированная переменная а не кто то присвоил 0?
С реализацией такого предложения будет не важно, присвоил ли кто-то 0, или оно там само.
Предсказуемость в том, что даже если 0 там не есть то, что хотели, ошибочное поведение будет стабильным, а не зависеть от конфигурации, компилятора, ОС, и того, какая функция вызывалась на этом стеке раньше.
Здравствуйте, Alexander G, Вы писали:
AG>Ну вот какого хрена в век, когда лямбды уже не вызывают "это ты выпендрился?"-реакцию на код ревью, когда все самые необходимые смарт-поинтеры уже есть в std, а в boost есть вообще все нужные, до сих пор можно наткнуться на непредсказуемую инициализацию переменных?
Потому, что массивы бывают длинны.
AG>
AG>int count;
AG>RegQueryValue(count); // забыли проверить возвращаемое значение
AG>for (int i = 0 ; i < count ; i++) // и приплыли - цикл повторяется непредсказуемое количество раз
AG>
А что собственно вы тут собрались проверять?
AG>Почему не введут инициализацию для всех простых типов?
А зачем она нужна? Если вы про приведённый пример, то хочется спросить, почему он не записан так:
const int count = RegQueryValue();
for (int i = 0 ; i < count ; i++)
AG>Для маньяков, которые не желают "платить за то, что не используют", можно же ввести синтаксис для "старой доброй русской рулетки".
Обратная совместимость важнее удобства.
AG>Может, это можно протянуть как пропозл?
Я против.
12/20/2013 12:24 PM, skeptic пишет:
> Как то слишком уж радикально ты...
Просто надоело быть толерантным здесь. Как не почитаешь идеи по С++
здесь, так за голову хватаешься, страшно становится.
Причем 90% обсуждений в 2 стилях, а как мне забомбить вот такую странную
нетривиальную фигню в коде (шоб никто не догадался) и ой, а чей-то у
меня память течет, нет ли доктора-телепата.
Здравствуйте, Alexander G, Вы писали:
AG>Здравствуйте, skeptic, Вы писали:
S>>Какой предсказуемостью? Как ты узнаешь что 0 это неинициализированная переменная а не кто то присвоил 0?
AG>С реализацией такого предложения будет не важно, присвоил ли кто-то 0, или оно там само.
AG>Предсказуемость в том, что даже если 0 там не есть то, что хотели, ошибочное поведение будет стабильным, а не зависеть от конфигурации, компилятора, ОС, и того, какая функция вызывалась на этом стеке раньше.
Ну, по спец.синтаксису я резко против, по понятным причинам — поломается много кода.
А по дефолтному присваиванию я думаю это не решит проблемы, зато добавит их разработчикам стандарта и компиляторов.
Ну и всё таки не ясно как выбирать дефолтные значения для разных типов?
Здравствуйте, skeptic, Вы писали:
S>Ну и всё таки не ясно как выбирать дефолтные значения для разных типов?
Они уже давно выбраны.
Я привёл выше синтаксис как до них добраться, вот другой синтаксис:
template<class T>
void InitializeDefault()
{
T t = T(); // для чисел - 0, для bool - false, для указателей - nullptr, для классов - дефолтный конструктор.
// на большинстве платформ двоичное представление этих значений - все байты нули.
}
Здравствуйте, Alexander G, Вы писали:
AG>Предсказуемость в том, что даже если 0 там не есть то, что хотели, ошибочное поведение будет стабильным, а не зависеть от конфигурации, компилятора, ОС, и того, какая функция вызывалась на этом стеке раньше.
в целом согласен, что пока мы в прошлом веке, т.к. спотыкаемся о подобные проблемы. рандомные баги из-за неинициализированных данных очень неприятны. хочется, чтобы программы вели себя детерминировано и баги можно было легко воспроизводить
проблему можно частично решать не на уровне языка, а на уровне средств : компиляторы должны выявлять такие моменты и очень часто это довольно простой код (члены класса в конструкторе не инициализируются, переменные на стеке)
Здравствуйте, Alexander G, Вы писали:
AG>Ну вот какого хрена в век, когда лямбды уже не вызывают "это ты выпендрился?"-реакцию на код ревью, когда все самые необходимые смарт-поинтеры уже есть в std, а в boost есть вообще все нужные, до сих пор можно наткнуться на непредсказуемую инициализацию переменных?
Потому что функция в случае неудачи может
— не инициализировать
— инициализировать удобным дефолтным или сигнальным значением (0)
— инициализировать неудобным сигнальным значением (-1 или 0xFFFFFFFF, или 0xDEADFACE какое-нибудь)
— инициализировать случайным мусором
Выход из этого — протаскивание в API самонесущих типов — boost::optional, например. Только это очень недружественно для FFI.
AG>Почему не введут инициализацию для всех простых типов? AG>Для маньяков, которые не желают "платить за то, что не используют", можно же ввести синтаксис для "старой доброй русской рулетки".
Специально для маньяков, которые желают платить, есть уже синтаксис с явной инициализацией...
Потому что забытый ноль ничем не хуже и не лучше забытого мусора. Такая же логическая ошибка, только более регулярная: будет ходить не по разным граблям, а по одним и тем же.
AG>Может, это можно протянуть как пропозл?
Идея прикольная, но может оказаться достаточно дорогой.
Лучше уж ввести какую-нибудь прагму #pragma zeroinit, которая форсировала бы инициализацию всех переменных подряд.
Здравствуйте, B0FEE664, Вы писали:
BFE>Потому, что массивы бывают длинны.
Принимается.
Хотя я предложил и варианты эскейпа для явной не-инициализации, которые можно применить и к массивам.
int a[1000] = { void };
[[uninitialized]]
int a[1000];
AG>>RegQueryValue(count); // забыли проверить возвращаемое значение
BFE>А что собственно вы тут собрались проверять?
Это функция некоторого system API или legacy API, сообщающая результат через код возврата, который надо было бы проверить.
BFE>Обратная совместимость важнее удобства.
Компиляция старого кода не ломается же.
Да, перформанс инициализации массивов ломается в некоторых случаях.
Здравствуйте, Alexander G, Вы писали:
AG>Ну вот какого хрена в век, когда лямбды уже не вызывают "это ты выпендрился?"-реакцию на код ревью, когда все самые необходимые смарт-поинтеры уже есть в std, а в boost есть вообще все нужные, до сих пор можно наткнуться на непредсказуемую инициализацию переменных?
AG>
AG>int count;
AG>RegQueryValue(count); // забыли проверить возвращаемое значение
AG>for (int i = 0 ; i < count ; i++) // и приплыли - цикл повторяется непредсказуемое количество раз
AG>
Найдите 10 отличий:
int count;
if (ERROR_SUCCESS != RegQueryValue(count)) // не забыли проверить возвращаемое значениеbreak; // return, continue, throw, etc - короче, включаем мозги по ситуацииfor (int i = 0 ; i < count ; i++) // и не приплыли - цикл повторяется предсказуемое количество раз
Здравствуйте, Alexander G, Вы писали:
S>>Какой предсказуемостью? Как ты узнаешь что 0 это неинициализированная переменная а не кто то присвоил 0? AG>С реализацией такого предложения будет не важно, присвоил ли кто-то 0, или оно там само. AG>Предсказуемость в том, что даже если 0 там не есть то, что хотели, ошибочное поведение будет стабильным, а не зависеть от конфигурации, компилятора, ОС, и того, какая функция вызывалась на этом стеке раньше.
Я бы предпочёл нестабильное поведение на ошибочном коде — пусть ошибки дают о себе знать как можно раньше. valgrind или какой-нибудь sanitazer прикрученный к юнит или интеграционным тестам, поймал бы это (+ другие классы ошибок).
А то так и до two's complement int недалеко
Вот даже в твоём коде:
int count;
RegQueryValue(count);
for (int i = 0 ; i < count ; i++) // ладно, был бы ноль - был бы noop
;
// А тут-то что делать? RegQueryValue ведь вернул ошибку