12/20/2013 12:24 PM, skeptic пишет:
> Как то слишком уж радикально ты...
Просто надоело быть толерантным здесь. Как не почитаешь идеи по С++
здесь, так за голову хватаешься, страшно становится.
Причем 90% обсуждений в 2 стилях, а как мне забомбить вот такую странную
нетривиальную фигню в коде (шоб никто не догадался) и ой, а чей-то у
меня память течет, нет ли доктора-телепата.
Здравствуйте, Alexander G, Вы писали:
AG>Ну вот какого хрена в век, когда лямбды уже не вызывают "это ты выпендрился?"-реакцию на код ревью, когда все самые необходимые смарт-поинтеры уже есть в std, а в boost есть вообще все нужные, до сих пор можно наткнуться на непредсказуемую инициализацию переменных?
Потому что функция в случае неудачи может
— не инициализировать
— инициализировать удобным дефолтным или сигнальным значением (0)
— инициализировать неудобным сигнальным значением (-1 или 0xFFFFFFFF, или 0xDEADFACE какое-нибудь)
— инициализировать случайным мусором
Выход из этого — протаскивание в API самонесущих типов — boost::optional, например. Только это очень недружественно для FFI.
AG>Почему не введут инициализацию для всех простых типов? AG>Для маньяков, которые не желают "платить за то, что не используют", можно же ввести синтаксис для "старой доброй русской рулетки".
Специально для маньяков, которые желают платить, есть уже синтаксис с явной инициализацией...
Потому что забытый ноль ничем не хуже и не лучше забытого мусора. Такая же логическая ошибка, только более регулярная: будет ходить не по разным граблям, а по одним и тем же.
AG>Может, это можно протянуть как пропозл?
Идея прикольная, но может оказаться достаточно дорогой.
Лучше уж ввести какую-нибудь прагму #pragma zeroinit, которая форсировала бы инициализацию всех переменных подряд.
Здравствуйте, 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>Может, это можно протянуть как пропозл?
Я против.
Здравствуйте, Alexander G, Вы писали:
AG>Нет, я хочу, чтобы просто
Скажите, а вот:
struct megabyte_t {
char i[1048576];
};
int
foo(void)
{
struct megabyte_t x;
... /* lot of code here */
}
Вы как хотите чтобы компилилось?
То есть вы реально готовы пойти на скрытый оверхед в инициализации мегабайтной переменной на стеке нулями просто вот так на пустом месте? Я полагаю, ваше скромное предложение, формально обратно совместимое, реально поломает обратную совместимость в том смысле, что весь код написанный в old-style все равно придется переписывать на =undefined из-за немыслимых просадок по перфомансу в легаси.
Но это ещё ладно. А теперь представьте у вас хитрый и стрёмный volatile вот такого вида:
extern volatile int port_b; // это не переменная, это порт ввода-вывода
// чтение -- состояние боевого лазера
// запись команды: port_b = 1; -- уничтожение флота пришельцев
// port_b = 2; -- самоуничтожение
// port_b = 0; -- уничтожение планеты Земля
Вы точно хотите дефолтно инициализировать её нулём? Не предупреждая разработчиков?
Ну вот какого хрена в век, когда лямбды уже не вызывают "это ты выпендрился?"-реакцию на код ревью, когда все самые необходимые смарт-поинтеры уже есть в std, а в boost есть вообще все нужные, до сих пор можно наткнуться на непредсказуемую инициализацию переменных?
int count;
RegQueryValue(count); // забыли проверить возвращаемое значениеfor (int i = 0 ; i < count ; i++) // и приплыли - цикл повторяется непредсказуемое количество раз
Почему не введут инициализацию для всех простых типов?
Для маньяков, которые не желают "платить за то, что не используют", можно же ввести синтаксис для "старой доброй русской рулетки".
Варианты, как это можно сделать:
int i = uninitialized; // "uninitialized" - не спец. значение, а magic, работающий только в инициализаторах, означающий, что мы хотим адреналинаint i = void; // мы даже можем не вводить новый кейворд, если это так важно
[[uninitialized]]
int i; // придумали аттрибуты, значит почему бы не использовать
12/20/2013 12:11 PM, Alexander G пишет:
> Почему не введут инициализацию для всех простых типов?
Потому что тупую голову и кривые руки инструментом не поправишь.
Здравствуйте, Alexander G, Вы писали:
AG>Почему не введут инициализацию для всех простых типов?
предвижу такую проблему -- после того как это введут в стандарт и выйдут компиляторы это поддерживающие, народ перестанет иницилизировать переменные, а старые компиляторы останутся и начнется реальная непредсказуемость.
americans fought a war for a freedom. another one to end slavery. so, what do some of them choose to do with their freedom? become slaves.
AG>int count;
AG>RegQueryValue(&count); // забыли проверить возвращаемое значение
AG>for (int i = 0 ; i < count ; i++) // и приплыли - цикл повторяется непредсказуемое количество раз
AG>
Вероятно, вы имели ввиду выделенное.
AG>Почему не введут инициализацию для всех простых типов? AG>Для маньяков, которые не желают "платить за то, что не используют", можно же ввести синтаксис для "старой доброй русской рулетки". AG>Варианты, как это можно сделать: AG>
AG>int i = uninitialized; // "uninitialized" - не спец. значение, а magic, работающий только в инициализаторах, означающий, что мы хотим адреналина
AG>int i = void; // мы даже можем не вводить новый кейворд, если это так важно
AG>
Вы добавляете головной боли эмбеддед разработчикам. Не совсем понятно, что компилятор должен вставлять для случаев, связанных с регистрами железки, рассчитанными только на чтение, которые как-то мапятся на переменные. Или, например, для переменных из пространства ввода-вывода для процессоров с гарвардской архитектурой.
AG>
AG>[[uninitialized]]
AG>int i; // придумали аттрибуты, значит почему бы не использовать
AG>
То, что вы хотите, уже есть в эмбеддед, где существуют секции (сегменты), которые в известной степени позволяют прописывать правила размещения и инициализации переменных. Используются в сочетании с #pragma. И да, бывают случаи, когда глобальные переменные умышленно не инициализируются. Для того, например, чтобы информация была доступна после ресета процессора. В любом случае, момент инициализации досточно специфичен для каждого процессора и компилятора, чтобы быть легко стандартизированным.
Здравствуйте, Alexander G, Вы писали:
AG>Ну вот какого хрена в век, когда лямбды уже не вызывают "это ты выпендрился?"-реакцию на код ревью, когда все самые необходимые смарт-поинтеры уже есть в std, а в boost есть вообще все нужные, до сих пор можно наткнуться на непредсказуемую инициализацию переменных?
AG>
AG>int count;
AG>RegQueryValue(count); // забыли проверить возвращаемое значение
AG>for (int i = 0 ; i < count ; i++) // и приплыли - цикл повторяется непредсказуемое количество раз
AG>
Приучи себя к простейшим правилам написания безопасного кода, и подобные проблемы отпадут сами собой.
Здравствуйте, 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 ведь вернул ошибку
Здравствуйте, visual_wind, Вы писали:
_>Вы добавляете головной боли эмбеддед разработчикам. Не совсем понятно, что компилятор должен вставлять для случаев, связанных с регистрами железки, рассчитанными только на чтение, которые как-то мапятся на переменные. Или, например, для переменных из пространства ввода-вывода для процессоров с гарвардской архитектурой.
Ну вообще-то регистры железа обычно объявляются как дефайны с адресом... А не как переменные, смапленные на память.
AG>>
AG>>[[uninitialized]]
AG>>int i; // придумали аттрибуты, значит почему бы не использовать
AG>>
_>То, что вы хотите, уже есть в эмбеддед, где существуют секции (сегменты), которые в известной степени позволяют прописывать правила размещения и инициализации переменных. Используются в сочетании с #pragma. И да, бывают случаи, когда глобальные переменные умышленно не инициализируются. Для того, например, чтобы информация была доступна после ресета процессора. В любом случае, момент инициализации досточно специфичен для каждого процессора и компилятора, чтобы быть легко стандартизированным.
Нету этого в эмбедед. Он пишет в частности про стековые переменные, как ты их собрался класть в секции?
Опять же, никто тебе не мешает и под десктопом переменные по секциям раскладывать...
Здравствуйте, skeptic, Вы писали:
S>Какой предсказуемостью? Как ты узнаешь что 0 это неинициализированная переменная а не кто то присвоил 0?
С реализацией такого предложения будет не важно, присвоил ли кто-то 0, или оно там само.
Предсказуемость в том, что даже если 0 там не есть то, что хотели, ошибочное поведение будет стабильным, а не зависеть от конфигурации, компилятора, ОС, и того, какая функция вызывалась на этом стеке раньше.
Здравствуйте, Alexander G, Вы писали:
AG>Ну вот как
AG>Почему не введут инициализацию для всех простых типов?
AG>Для маньяков, которые не желают "платить за то, что не используют", можно же ввести синтаксис для "старой доброй русской рулетки". AG>Варианты, как это можно сделать:
мне кажется, ближе к С++ будет что-то такое:
auto i = unitialized<int>
ну и заодно, я предлагаю убрать наконец auto и const (сделав их модификаторами по умолчанию), а для того, чтобы избежать путаницы между объявлением новой переменной и заменой старой, ввести слово change. Ну и добавить нормальный кортежи, типа
(i, b) = ShittyFuncWhichReturnsIntAndBool();
Зачем это нужно? Просто именно код, состоящий исключительно из объявлений новых констант, вычисляемых из старых, вызывает у меня наибольшее эстетическое удовольствие.
Здравствуйте, Alexander G, Вы писали:
AG>Почему не введут инициализацию для всех простых типов?
Обратная совместимость + увеличится объём кода.
В силу того что компилятор выдаёт предупреждения по поводу неинициализированных переменных,
никому спец синтаксис для этого не нужен.
AG>Может, это можно протянуть как пропозл?
Здравствуйте, 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?
Здравствуйте, 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 там не есть то, что хотели, ошибочное поведение будет стабильным, а не зависеть от конфигурации, компилятора, ОС, и того, какая функция вызывалась на этом стеке раньше.
в целом согласен, что пока мы в прошлом веке, т.к. спотыкаемся о подобные проблемы. рандомные баги из-за неинициализированных данных очень неприятны. хочется, чтобы программы вели себя детерминировано и баги можно было легко воспроизводить
проблему можно частично решать не на уровне языка, а на уровне средств : компиляторы должны выявлять такие моменты и очень часто это довольно простой код (члены класса в конструкторе не инициализируются, переменные на стеке)
Здравствуйте, 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++) // и не приплыли - цикл повторяется предсказуемое количество раз
Здравствуйте, Mr.Delphist, Вы писали:
MD>Найдите 10 отличий: MD>
MD>int count;
MD>if (ERROR_SUCCESS != RegQueryValue(count)) // не забыли проверить возвращаемое значение
MD> break; // return, continue, throw, etc - короче, включаем мозги по ситуации
MD>for (int i = 0 ; i < count ; i++) // и не приплыли - цикл повторяется предсказуемое количество раз
MD>
К сожалению, не все таки умные.
В своё оправдание могу сказать только то, что я это не писал, оно мне досталось.
Здравствуйте, Alexander G, Вы писали:
AG>Здравствуйте, skeptic, Вы писали:
S>>Обратная совместимость
AG>С чем? Кто-то рассчитывает прочитать определённый мусор?
Нет, просто где-то незначительно, где-то может и ощутимо просядет производительность у всего C++ кода, которого дофига. Непонятно, в чем проблема ввести требование обязательной инициализации?
Здравствуйте, Кодт, Вы писали:
К>Потому что функция в случае неудачи может К>- не инициализировать К>- инициализировать удобным дефолтным или сигнальным значением (0) К>- инициализировать неудобным сигнальным значением (-1 или 0xFFFFFFFF, или 0xDEADFACE какое-нибудь) К>- инициализировать случайным мусором
Инициализация не приведёт к желаемому результату только в последних двух случаях.
В WinAPI я таковых не встречал. В WinAPI чаще первый случай, хотя изредка второй.
В других API последние два тоже редкость.
И то, хоть инициализация и не поможет, дополнительного вреда она не принесёт.
К>Такая же логическая ошибка, только более регулярная: будет ходить не по разным граблям, а по одним и тем же.
Я за регулярность. Чтобы ошибка, которая вылезла только у меня, вылезла и у чувака, который это закоммитил.
AG>>int count;
AG>>RegQueryValue(&count); // забыли проверить возвращаемое значение
AG>>for (int i = 0 ; i < count ; i++) // и приплыли - цикл повторяется непредсказуемое количество раз
AG>>
Здравствуйте, Alexander G, Вы писали:
BFE>>Потому, что массивы бывают длинны. AG>Принимается. AG>Хотя я предложил и варианты эскейпа для явной не-инициализации, которые можно применить и к массивам.
Не надо этого. Ключи компиляции или прагмы какие тут лучше подойдут.
AG>>>RegQueryValue(count); // забыли проверить возвращаемое значение BFE>>А что собственно вы тут собрались проверять? AG>Это функция некоторого system API или legacy API, сообщающая результат через код возврата, который надо было бы проверить.
Договорится не использовать напрямую. Всегда через обертку:
int ApiRegQueryValue(int& err)
{
int count = 0;
err = RegQueryValue(count);
return count;
}
Здравствуйте, Alexander G, Вы писали:
AG>К сожалению, не все таки умные. AG>В своё оправдание могу сказать только то, что я это не писал, оно мне досталось.
Прекрасно понимаю — быть по колено в legacy часть нашей профессии. Но часть нашей профессиональной ответственности — выправлять если не архитектуру (ибо не всегда апрувят), то хоть такие мелкие залепухи, чтобы линейный код был устойчивым к жизни. Благо в большинстве компаний для таких фиксов не требуется благословления менеджмента.
Здравствуйте, enji, Вы писали:
E>Здравствуйте, visual_wind, Вы писали:
E>Ну вообще-то регистры железа обычно объявляются как дефайны с адресом... А не как переменные, смапленные на память.
Обычно в этом дефайне содержится разыменованный указатель на volatile int, к которому приведен этот самый адрес.
AG>>>[ccode] E>Нету этого в эмбедед. Он пишет в частности про стековые переменные, как ты их собрался класть в секции? E>Опять же, никто тебе не мешает и под десктопом переменные по секциям раскладывать...
Здесь да, согласен, я протупил. Увы, стековые переменные никак не проинициализируешь, положив их в секцию.
Здравствуйте, Alexander G, Вы писали:
AG>Ну вот какого хрена в век, когда лямбды уже не вызывают "это ты выпендрился?"-реакцию на код ревью, когда все самые необходимые смарт-поинтеры уже есть в std, а в boost есть вообще все нужные, до сих пор можно наткнуться на непредсказуемую инициализацию переменных?
AG>
AG>int count;
AG>RegQueryValue(count); // забыли проверить возвращаемое значение
AG>for (int i = 0 ; i < count ; i++) // и приплыли - цикл повторяется непредсказуемое количество раз
AG>
AG>Почему не введут инициализацию для всех простых типов?
Повторяя вслед за Кодтом, "потому что забытый ноль и.т.д.".
Это не решение проблемы. В данном конкретном случае нужно было просто завернуть вызов в функцию с контролем и выбросом исключения.
Нужно просто правильно проектировать интерфейсы. Если используются старые библиотеки или системное API, то следует использовать их не напрямую, а через
облагораживающие прокладки.
Здравствуйте, Alexander G, Вы писали:
AG>Я привёл выше синтаксис как до них добраться, вот другой синтаксис: AG>
AG>template<class T>
AG>void InitializeDefault()
AG>{
AG> T t = T(); // для чисел - 0, для bool - false, для указателей - nullptr, для классов - дефолтный конструктор.
AG> // на большинстве платформ двоичное представление этих значений - все байты нули.
AG>}
AG>
Для перечислений что будет?..
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Alexander G, Вы писали:
AG>for (int i = 0 ; i < count ; i++) // и приплыли — цикл повторяется непредсказуемое количество раз
Никуда я не приплыл
void RegQueryValue(int count)
{
}
int _tmain(int argc, _TCHAR* argv[])
{
int count;
RegQueryValue(count); // забыли проверить возвращаемое значениеfor (int i = 0 ; i < count ; i++) // и вот здесь выдается окно Run-Time Check Failure #3 - The variable 'count' is being used without being initialized.return 0;
}
Здравствуйте, B0FEE664, Вы писали:
BFE>Потому, что массивы бывают длинны.
Можно ввести понятие "статический массив размера N, у которого имеют смысл только первые M членов".
N — определяется при создании массива и меняться при его жизни не может. К сожалению, оно пока что в С++ может существовать лишь как константа времени компиляции, ведь alloca — некроссплатформенная хрень.
M — может меняться со временем.
Попытки обратиться к членам, находящимся за M-ым, пресекаются ассертом.
Так вот, массивы можно по умолчанию инициализировать как "изначально M=0". Если надо считать в массив информацию — то по одному наращиваем M, добавляя в конец конкретное значение.
Если надо сразу резко увеличить M — то тогда все новые элементы либо заполняются заранее оределённым значением, либо для них вызывается конструктор по умолчанию.
AG>>>RegQueryValue(&count); // забыли проверить возвращаемое значение
AG>>>
AG>Забыл указать, я о С++, а не о С. AG>Это — ссылка.
Если таки RegQueryValue -- это не С-шная апишная функция, а таки С++ обёртка, то просто её надо было писать по-человечески, а не на компилятор пенять.
Например оно могло бы быть примерно таким:
int RegQueryValue( int& errCode, int defaultValue = 0 );
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Erop, Вы писали:
E>Если таки RegQueryValue -- это не С-шная апишная функция, а таки С++ обёртка, то просто её надо было писать по-человечески, а не на компилятор пенять. E>Например оно могло бы быть примерно таким:
int RegQueryValue( int& errCode, int defaultValue = 0 );
Зело убого смотрится, не согласен.
В таких случаях нужно исключение бросать, его проигнорировать невозможно. К тому же вылететь по не пойманному исключению намного лучше, чем посчитать погоду в африке.
В BCL очень грамотно подошли к этому вопросу: названия тех методов, которые не бросают исключение начинается Try, например: Double.TryParse() не бросает, а Double.Parse().
ЗЫ: За игнорирование возвращаемых значений нужно бить по рукам, желательно автоматически. Если уж хочется проигнорировать, то нужен способ сделать это явно (например, подавить варнинг директивой).
Всё сказанное выше — личное мнение, если не указано обратное.
12/23/2013 12:33 AM, Философ пишет:
> Зело убого смотрится, не согласен. > В таких случаях нужно исключение бросать, его проигнорировать > невозможно.
Бред. Все определяется только задачей.
Здравствуйте, Философ, Вы писали:
Ф>Зело убого смотрится, не согласен. Ф>В таких случаях нужно исключение бросать, его проигнорировать невозможно. К тому же вылететь по не пойманному исключению намного лучше, чем посчитать погоду в африке.
Это очень зависит от всего на свете. Например от кдинг стайла принятого в команде. Исключения вообще не везде разрешены, даже, ну и потом, даже там, где разрешены, их не обязательно можно будет бросать из этой функции...
Обычно таки исключения -- это исключительная ситуация же. Ну, например, не работает риестр вообще, или там,, нет доступа к нужной переменной.
А вот ситуация, что ключа просто нет, не задан, вполне может быть и штатной...
Кстати, исключение проигнорировать так же просто, как и специально заведённую для кода ошибки переменную...
Ф>В BCL очень грамотно подошли к этому вопросу: названия тех методов, которые не бросают исключение начинается Try, например: Double.TryParse() не бросает, а Double.Parse().
Есть разные соглашения и подходы к тому, как и для чего надо использовать исключения.
Я, например, сторонник их использования, но только для реально исключительных ситуаций...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
+1 Для многих объектов (в том числе встроенных типов) вполне хорошо и привычно находиться в частично инициализированном состоянии, в котором ему либо что-то будет присвоено, либо он будет разрушен. Я с этим смирился, а некоторые видимо нет .
Здравствуйте, skeptic, Вы писали:
S>Здравствуйте, Alexander G, Вы писали:
AG>>Здравствуйте, skeptic, Вы писали:
S>>>Какой предсказуемостью? Как ты узнаешь что 0 это неинициализированная переменная а не кто то присвоил 0?
AG>>С реализацией такого предложения будет не важно, присвоил ли кто-то 0, или оно там само.
AG>>Предсказуемость в том, что даже если 0 там не есть то, что хотели, ошибочное поведение будет стабильным, а не зависеть от конфигурации, компилятора, ОС, и того, какая функция вызывалась на этом стеке раньше.
S>Ну, по спец.синтаксису я резко против, по понятным причинам — поломается много кода. S>А по дефолтному присваиванию я думаю это не решит проблемы, зато добавит их разработчикам стандарта и компиляторов. S>Ну и всё таки не ясно как выбирать дефолтные значения для разных типов?
А в чем проблема с дефолтными значениями? Во всяких там джавах именно так и делают — инициализируют все переменные по умолчанию.