Comments 354
Земля – крестьянам!
Заводы – рабочим!
Планету — хакерам!!!
(Народная Сишная Республика)
Autonomous Republic of C++
Столмана — в прокуроры!
Балмера — в жириновские!
Ваш Кэп.
Зато знаю множество толковых переводчиков с русского на Си
Мне почему-то все предельно ясно. Что я делаю не так?
int need_job = 14;
struct war* have_skill = (struct war*) malloc(16);
Stork: need_job += 'a';
if (need_job && have_skill) {
goto Stork;
}
Как-то так, например
#define esli if
#define poshel_v goto
esli (nuzhna_rabota && est_znaniy) {
poshel_v Stork;
}
Быть уверенным в том, что записано в переменную и записано ли в нее что-либо мы знать не можем.
Точно так же похоже, что словами «need_job» и «have_skill» авторы хотели обозначить «требуется работа» и «имеется навык».
И эти размышления не определяют, как реклама должна была бы выглядеть по закону. Это всего лишь ответ на ваш вопрос «Каким мог бы быть перевод?».
Перейти ~Stork;
КонецЕсли;
Пока Истина Цикл
Для Каждого Элемент Из МассивЭлементов Цикл
Если ВыполнениеУсловия(Элемент) Тогда
Перейти ~ВыходИзДвойногоЦикла;
КонецЕсли;
…
КонецЦикла;
КонецЦикла;
~ВыходИзДвойногоЦикла:
// продолжение вычислений
В конце-концов, что мешало им сделать просто блок-схему! :)
Разве главное не происхождение?
Определение этничности строится также на основе культурной самоидентификации этнической общности по отношению к другим общностям (этническим, общественным, политическим), с которыми она находится в фундаментальных связях.» https://ru.wikipedia.org/wiki/Этнос
«Этнос — исторически сложившаяся этническая общность — племя, народность, нация.
Нация — исторически сложившаяся устойчивая общность людей, образующихся в процессе формирования общности их территории, экономических связей, литературного языка, особенностей культуры и духовного облика.» С. И. Ожегов
Общей исторической памятью, надо полагать, является git log
ядра linux?
Вообще, в современном мире национальность определяется самоидентификацией. Вы сами должны определиться (если хотите), кто вы больше — русский или сишник.
При переписи населения вас просто попросят указать, кто вы по национальности, не вдаваясь в подробности национальностей бабушек или дедушек, а если вы не захотите говорить переписчику свою национальность, настаивать не имеют права.
http://blogovodoved.livejournal.com/4059.html
Напишите, если знаете такие произведения.
вот из за таких как вы из повершела убрали GOTO
убрали ещё на этапе разработкиЯ не знаком с данным продуктом, но по факту получается, что GOTO нет в первоначальном релизе… т.е. по задумке авторов изначально оператор безусловного перехода не предусмотрен. Вам не кажется, что «такие как я» тут как бы не причем, т.к. GOTO не было в релизе от слова совсем.
в замен дали break :label
Но както через жо
В Windows PowerShell иметь метки могут только ключевые слова цикла, такие как Foreach, For, While.
в результате из цикла можно выскочить только в начало другого цикла или в конец этого.
Экспресс в середину цикла? да кому оно надо подумали они.
так ведь разработчики и относятся к ненавистникам gotoВы напрасно ярлыки развешали. Я не ненавистник, я его просто не использую в си
Приведите пример безусловного перехода в середину цикла на си…
#include <stdio.h>
int main(void)
{
int P;
int PP;
int count=0;
int H=50000000;
int N=61000000;
if (H%2==0) {H++;}
while (H<=N)
{
P=1;
PP=round(sqrt(H));
do
{
P=P+2;
if (H%P==0) {goto E;}
}
while (P<=PP);
count++;
E: H=H+2;
}
printf( "%d\n", count );
getchar();
return 0;
}
Как вы их обрабатываете без goto?
По факту ошибки выполняется throw(чё произошло) и ловится в catch. Дальше уже пляшем.
Возможно, есть что-то ещё.
Могу осторожно согласиться, что я просто не встречался с задачами, где без goto никак.
Второй способ описан ниже и применим только для C, но не для C++.
bool go_out = false;
for(int x = -1024; (x <= 1024) && (!go_out); x++){
for(int y = -1024; (y <= 1024) && (!go_out); y++){
// any operations
...
// block end
if(m[x][y] == 'X'){
go_out = true;
}
}
}
Чем не решение? Случай синтетический, лично не доводилось использовать такие конструкции.
1. Обернуть код в функцию (предпочтительно).
2. Написать двумерный итератор (тоже хороший вариант).
3. После go_out поставить break, и проверять условие только во внешнем цикле.
4. Заменить go_out на x = 1025, y = 1025 (крайне нежелательно).
Goto — это нативная команда ассемблера, JMP и куча нативных Jxx, из этого состоит весь компилированный код.
Вместо этого в твоём примере тратим память на абсолютно ненужную переменную, на доступ к памяти, на чтение памяти каждый раз в этой миллионной интерации, вместо того чтобы сделать один goto и съэкономить миллиадры циклов процессора. Даже если go_out будет лежать в регистре, это всё равно не бесплатная операция проверки.
А потом удивляемся, почему у нас всё везде тормозит на 8 ядрах и 4х гигагерцах, потому что каждый уровень разработчиков абстракции побоялся где-то чуть оптимизировать код и побоялся «богомерзкого» нативного goto, якобы «кто-то сказал что так нельзя». Эти же люди бояться писать без «ооп», делают фабрики фабрик даже там где это не нужно и совсем не думают о производительности.
int i, j, k;
try
{
for (i = 0; i < 100; i++)
{
for (j = 0; j < 100; j++)
{
for (k = 0; k < 100; k++)
{
if (k == 50)
{
throw new IndexOutOfRangeException();
}
}
}
}
}
catch (IndexOutOfRangeException) {}
А goto просто прёт напролом.
Насколько я понимаю.
On exit from a scope (however accomplished), destructors (12.4) are called for all constructed objects with automatic storage duration (3.7.2) (named objects or temporaries) that are declared in that scope, in the reverse order of their declaration.
Тогда это не просто jmp куда-то на метку, получается, а сложная конструкция.
It is possible to transfer into a block, but not in a way that bypasses declarations with initialization. A program that jumps from a point where a local variable with automatic storage duration is not in scope to a point where it is in scope is ill-formed unless the variable has POD type and is declared without an initializer.
Мутная тема. По крайней мере в С++, где не только POD.
private void doFirstCycle() {
int j;
for (j=0; j<100; j++) {
doYourJob();
if (this.haveToBreak) {
doSecondCycle(3, 200);
break;
}
}
return;
}
private void doSecondCycle(from, to) {
int i;
for (i=from; i<to; i++) {
doAnotherJob();
return;
}
В нужном месте той огромной нечитаемой функции, из одного из циклов которой нужно прыгать в середину другого, вместо цикла вставляете вызов функции. Заодно и читаемость повысится.
— надо начать с doAnotherJob_2();
private void doSecondCycle(from, to) {
int i;
for (i=from; i<to; i++) {
doAnotherJob_1();
doAnotherJob_2();
return;
}
private enum dirtyCycleJumper {
fromFirst,
fromSecond
}
private void doSecondCycle(int from, int to, dirtyCycleJumper startFrom) {
int i;
for (i=from; i<to; i++) {
switch (startFrom) {
case fromFirst: doAnotherJob_1();
case fromSecond: doAnotherJob_2();
}
startFrom = dirtyCycleJumber.fromFirst;
}
return;
}
Вызываем doSecondCycle(3, 200, dirtyCycleJumper.fromSecond).
С такими требованиями, действительно, goto будет удобнее. Но случай какой-то уж больно маргинальный.
когда руки дойдут сравню различные способы обойти goto где он действительно просится( запрыгнуть в середину цикла), но беглый взгляд подсказывает что goto должен отработать быстрее вызова функции.
private void doFirstCycle() {
int j;
for (j=0; j
И живет он теперь почти как ИИ, хрен знаешь что выкинет в следующий раз.
Лучше переписать так чтобы в принципе не нужно было из середины цикла кудато прыгать
можно сделать goto на второе
или сделать ещё одну переменную и break`ом оборвать первый цикл, а потом пройтись по куче if, когда количество итераций плавно так уходит за 6 лямов, каждый if в цикле делает вас печальнее.
a: while(true) {
while(true) {
if (Math.random() < 0.5) {
break a;
}
}
}
Но первые лет 5 и после тогда отвлекался на С. Модуль ядра линукс даже помнится писал.
Но нигде алгоритм не упирался в goto. Так, что прям без него вот ну никак.
И даже на c++ не всегда RAII использую. Но обхожусь без goto и, повторю, ни разу не вспоминал про него в духе: эх, тут goto просится.
int do_or_fail(void)
{
FILE *f1, *f2, *f3;
int retval = 0;
if(!(f1=fopen("aaa.txt","r")))
return 0;
if(!(f2=fopen("bbb.txt","r")))
goto cleanup_f1;
if(!(f3=fopen("ccc.txt","r")))
goto cleanup_f2;
/* ... do something with the files .... */
retval = 1;
cleanup_f3:
fclose(f3);
cleanup_f2:
fclose(f2);
cleanup_f1:
fclose(f1);
return retval;
}
Без него при каждом открытии файла был бы иф с кучей команд освобождения ресурсов и возвратом по ошибке. При этом код освобождения ресурсов дублируется, что загромождает программу. А еще в таком коде легко допустить ошибку.
Также не стоит забывать, что обстановка в ядре ОС сильно отличается от обстановки в user-space. В user-space у вас обычно есть потоки, и каждый из них выполняет какой-то длинный код, захватывая ресурсы и освобождая их. Здесь RAII работает хорошо. А в ядре у вас в основном callbacks (в числе которых ISR и DPC), короткие функции, которые должны быстро отработать и выйти. Захваченные ресурсы зачастую удерживаются между вызовами этих функций, а вызваны они могут быть в контексте разных потоков и процессов. Так что RAII в чистом виде здесь имеет ограниченное применение, как, впрочем, и вышеприведенный паттерн с goto.
Какие-то костыли, конечно, можно придумать, но от этого вся красота и удобство RAII сходят на нет.
А по вашему вообще ООП без исключений невозможно получается?
Суть RAII заключается не в том, чтобы бросить исключение в конструкторе.
Я не говорил, что «бросить исключение в конструкторе — это суть RAII».
Но возможность бросить исключение в конструкторе является критической для реализации RAII так, чтобы код получался красивым и корректным. Поясните пожалуйста, как можно реализовать RAII без исключений в конструкторе?
А по вашему вообще ООП без исключений невозможно получается?
Этого я тоже не говорил.
Так что вовсе не обязательно конструктор должен бросать исключение.
Ну и если могут быть ошибки, можно оставить проверку ошибок для отдельных функций, а не кидать исключения.
Конструктор открыл файл.
Внешний код вызвал функцию проверки всё-ли в порядке.
Файловые потоки stl c++ так и работают.
В общем случае, ошибки при захвате ресурса может и не быть.
Это скорее исключение, чем правило. В подавляющем большинстве случаев функции захвата ресурсов могут вернуть отказ. На то они и ресурсы, чтобы исчерпываться.
Ну и если могут быть ошибки, можно оставить проверку ошибок для отдельных функций, а не кидать исключения.
И тогда RAII превращается в адъ.
Мы в данной ветке обсуждаем паттерн goto для досрочного возврата из функции с очисткой ресурсов. Выше была приведена реализация на C для случая открытия трех файлов. Те, кто говорил здесь о RAII, имели в виду, что с помощью RAII эта задача решается проще. С этим можно согласиться. Вот пример реализации с помощью RAII:
class RaiiFile
{
public:
RaiiFile(const char* filename): f(fopen(filename,"r")) {if(!f) throw std::runtime_error("File open failed");}
~RaiiFile() { fclose(f); }
private:
FILE* f;
}
void do_or_fail(void) // Throws an exception on failure
{
RaiiFile f1("aaa.txt");
RaiiFile f2("bbb.txt");
RaiiFile f3("ccc.txt");
/* ... do something with the files .... */
// The files will be correctly closed on return or exception anywhere in this function
}
Попробуйте сделать то же самое без исключений в конструкторах. Потом сравните с вариантом на C с goto.
И память может быть уже выделена и уже после отдаётся для управления RAII-объекту.
И мьютекс уже заранее создан и отдается на блокирование RAII-объекту.
Вы не путайте
Уважаемый, пожалуйста не используйте в разговоре со мной такой поучительный тон. Еще неизвестно, кто из нас что путает.
И мьютекс уже заранее создан и отдается на блокирование RAII-объекту.
То, что он заранее создан, не гарантирует, что функция блокировки по мьютексу завершится успешно. В винде, например, есть такой код возврата WAIT_ABANDONED. Можете погуглить, если интересно.
Ну и даже если вы найдете примеры, когда ошибка в конструкторе возникнуть не может — все же это не опровергает, что при захвате, выделении, или каких угодно операций в отношении ресурсов чаще встречается ситуация, когда может возникнуть ошибка, чем наоборот. И пример с goto, с которого началось обсуждение, как раз возник из задачи обработки ошибок. К чему вы вообще сюда приплетаете участки кода, где ошибок возникать не может?
Вам выше был задан вопрос, можете ли вы реализовать обработку ошибок на базе RAII, но без исключений. И привести пример для сравнения. Вопрос остался без ответа. Не можете?
«В подавляющем большинстве случаев функции захвата ресурсов могут вернуть отказ. На то они и ресурсы, чтобы исчерпываться.»
и не делаете разницы между выделением ресурса и его захватом, то мне ничего не остаётся как указать на этот недочёт, уважаемый :)
Теперь что касается RAII без исключений: RAII это всего лишь ООП-техника управления ресурсами. Вы отказались от «своих» слов, предложенных мною:
«А по вашему вообще ООП без исключений невозможно получается?
Этого я тоже не говорил.»
Стало быть согласны ООП и исключения — не две стороны одной медали. И одно без другого вполне может существовать.
Стало быть и RAII можно сделать без исключений.
И ошибочки после конструктора проверить незазорно (я привёл пример работы с файловыми потоками).
Или, например, какая может возникнуть ошибка в конструкторе какого-нибудь авто указателя, которому сдают на управление память? Что он не сможет в свою внутреннюю переменную-указатель положить переданное в параметре значение?
Вы написали, что без исключений нельзя построить RAII.
Для того, чтобы опровергнуть это утверждение — достаточно привести хотя бы один пример.
Указанной парочки хватит?
и не делаете разницы между выделением ресурса и его захватом
По сути дела, с точки зрения RAII, это одно и то же. В обоих случаях ресурс надо вернуть (очистить, освободить), и в обоих случаях может возникнуть отказ.
то мне ничего не остаётся как указать на этот недочёт, уважаемый :)
Вы так старательно заостряете внимание на мелочах — вам явно хочется увести обсуждение в сторону от исходной темы.
Стало быть согласны ООП и исключения — не две стороны одной медали. И одно без другого вполне может существовать.
Стало быть и RAII можно сделать без исключений.
Из одного не следует другое. Я вам дважды предлагал привести пример реализации RAII без исключений для открытия файлов и обработки ошибок их открытия. В ответ — тишина. Если можно сделать — сделайте. Думаю, что на написание ваших сообщений с придирками к мелочам ушло больше вашего времени, чем на написание предлагаемого примера.
И ошибочки после конструктора проверить незазорно (я привёл пример работы с файловыми потоками).
«Проверяние ошибочек после конструктора» — это по сути не RAII, так как при использовании RAII ресурс выделен (захвачен), пока существует объект, им управляющий, и наоборот.
Вы привели в пример весьма неудачное решение из стандартной библиотеки. Создается, к примеру, объект ofstream, но существование этого объекта не означает возможность записи в поток. Эта архитектура появилась до изобретения RAII в C++ (а возможно — и до введения в этот язык механизма исключений) и сохраняется лишь как наследство с целью совместимости.
Для сравнения возьмите приведенный выше класс RaiiFile. Здесь у объекта имеется инвариант: пока он существует, файл открыт, как только удаляется — файл закрыт. С такой архитектурой работать значительно проще.
Вы написали, что без исключений нельзя построить RAII. Для того, чтобы опровергнуть это утверждение — достаточно привести хотя бы один пример.Указанной парочки хватит?
Ваши примеры мое утверждение не опровергают. Случай отсутствия возможности ошибок в конструкторе не охватывает все области применения RAII, поэтому он не может рассматриваться как общее решение задачи. Что же касается ofstream — аргументы приведены выше. Это неполноценное RAII, так как не соблюдается инвариант.
Вы утверждаете, что RAII без исключений невозможно.
Я привёл 2 опровергающих примера. С точки зрения формальной логики достаточно и одного.
Вы акцентировали внимание на удобном Вам примере с файловыми потоками, не считая их по сути RAII. По вашему — RAII это однозначность: если объект есть — ресурс захвачен.
По мне так более важная работа происходит в деструкторе. Он «автоматически», самостоятельно, незаметно для программиста подчищает ресурсы. Конструктор же работает «под управлением» программиста и так или иначе — всё-равно проверка его работы осуществляется. Или вызвать функцию или ловить исключение. Всё-равно писать код. Или сразу после создания объекта или «где-то внизу». Это уже не принципиально и не является сутью RAII.
Суть его — в деструкторе.
И в этом смысле файловые потоки stl — самое обычное RAII.
А с какой «архитектурой» работать проще: с исключениями или с «ручной» проверкой ошибок — по большей части вопрос вкуса.
У исключений есть, на мой взгляд, только 2 существенных плюса:
1. Исключение не пропустишь. Вручную ошибку можно забыть проверить или, если какая-то стороняя библиотека, то в новой версии в ней могут появиться новые исключения.
Но, опять таки, что лучше — упавшая на непойманном исключении программа или программа не проверившая ошибку и ковыляющая дальше — зависит от ситуации.
2. Иерархия классов исключений, которая позволяет ловить их не по одиночке, а группами.
Я привёл 2 опровергающих примера. С точки зрения формальной логики достаточно и одного.
Вы не привели ни одного опровергающего примера.
Здесь ситуация такая же, как если бы я утверждал, что корни полинома 8й степени в общем случае нельзя найти аналитически, а вы «опровергали» бы это, приводя в пример уравнение вида x^8=64, которое таким образом решить можно.
Наличие легких частных случаев не означает, что общая задача решается так же легко, как эти частные ее случаи.
Вы акцентировали внимание на удобном Вам примере с файловыми потоками, не считая их по сути RAII.
Удобный мне пример? Ни в коем случае. Это был удобный вам пример, который вы настойчиво проталкиваете к обсуждению. Я вынужден был его разобрать, раз вы так настаивали.
По вашему — RAII это однозначность: если объект есть — ресурс захвачен.
Ну а как иначе? Прочитайте, что ли, определение RAII. «Resource acquisition IS initialization». В случае с ofstream, объект после отработки конструктора инициализирован? Инициализирован. Ресурс захвачен? Не захвачен. Какое здесь может быть RAII?
По мне так более важная работа происходит в деструкторе.
Деструкторы — это необходимый механизм реализации RAII в C++. Но недостаточный. Другим необходимым механизмом являются исключения.
Конструктор же работает «под управлением» программиста и так или иначе — всё-равно проверка его работы осуществляется. Или вызвать функцию или ловить исключение.
Полагаю, под фразой «вызвать функцию» вы имели в виду «выполнить проверку»?
Вот вы написали выше про деструктор: «Он «автоматически», самостоятельно, незаметно для программиста подчищает ресурсы».
Это очень важное преимущество. За счет автоматизации подчистки ресурсов исключаются ситуации, когда программист «забыл» это сделать вручную. Также код очистки ресурсов не загромождает программу, облегчая понимание ее основной логики.
Но не деструкторами едиными жив RAII. Есть еще вторая проблема — проверка ошибок при захвате ресурсов и досрочный выход из функции в случае ошибки. Этим в C++ занимается механизм исключений в конструкторах. Благодаря ему, вашими же словами: «автоматически», самостоятельно, незаметно для программиста проверяются ошибки при захвате ресурсов.
Не находите сходство? В обоих случаях идет автоматизация одного из важных аспектов работы с ресурсами.
Отсутствие исключений в конструкторах делает невозможной автоматизацию проверки ошибок при захвате ресурсов. От этого попытка реализации RAII в C++ теряет, грубо говоря, половину своих преимуществ.
А с какой «архитектурой» работать проще: с исключениями или с «ручной» проверкой ошибок — по большей части вопрос вкуса.
Если распространить вашу логику на деструкторы — то получится, что RAII можно сделать и без деструкторов, вручную очищая ресурсы, и это лишь вопрос вкуса.
1. У Вас прямым текстом было написано:
«RAII без исключений невозможно».
Никаких общих или не общих случаев. Просто написано: невозможно.
Я привёл примеры — ну хорошо, не нравятся Вам файловые потолки, но Вы уже второй раз игнорируете второй пример с автоуказателем.
У которого в конструкторе не может быть ошибок.
2. Ваши слова:
«В случае с ofstream, объект после отработки конструктора инициализирован? Инициализирован.»
С чего Вы взяли? Он — создан, а вот инициализирован он до конца (в его, объекта семантике) — это нужно у него узнать.
Да, спросить:
if (!myFileStream) return;
Или, как Вы настаиваете, ловить исключение:
try
{
…
}
catch (Exception& e)
{
return;
};
Оба варианта годятся.
Мне вариант с исключениями не нравится громоздкостью. Плюс Вы же сами упомянули, что исключения — «тяжелый» механизм.
Но не вижу причин делать тот или иной механизм обработки ошибок неотъемлемым признаком RAII.
3. «Вот вы написали выше про деструктор: «Он «автоматически», самостоятельно, незаметно для программиста подчищает ресурсы».
Это очень важное преимущество.»
Преимущество… Я настаиваю, что именно это и есть суть RAII. А не принцип проверки ошибок инициализации.
4.«Но не деструкторами едиными жив RAII. Есть еще вторая проблема — проверка ошибок при захвате ресурсов и досрочный выход из функции в случае ошибки. Этим в C++ занимается механизм исключений в конструкторах. Благодаря ему, вашими же словами: «автоматически», самостоятельно, незаметно для программиста проверяются ошибки при захвате ресурсов.»
Во-первых, Вы сами упоминали, что исключения — это не единственный способ сообщить об ошибке.
Во-вторых, никакой «автоматической проверки ошибок» исключениями — нет. Программист всё-равно должен написать код проверки.
Но по Вашему — не в месте возникновения ошибки, а в блоке catch. Ну, как я уже писал, это дело вкуса и к RAII не имеет отношения.
Единственное что однозначно характеризует RAII — это работа деструктора.
И именно поэтому не катит ваше утверждение:
«Если распространить вашу логику на деструкторы — то получится, что RAII можно сделать и без деструкторов, вручную очищая ресурсы, и это лишь вопрос вкуса.»
1. У Вас прямым текстом было написано:
«RAII без исключений невозможно».
Никаких общих или не общих случаев. Просто написано: невозможно.
Хорошо, уточню: RAII невозможно без исключений в общем случае. Если вы считаете это важным уточнением — то надеюсь, что этим ваше стремление к точности в мелочах удовлетворено?
Замечу также, что до того, как вы влезли в это обсуждение, обсуждалась задача обработки ошибок при захвате ресурсов и ее решение с помощью RAII. Из одного этого читателю, знакомому с RAII, должно было быть понятно, что частные случаи, когда ошибка при захвате ресурса возникнуть не может, не имеют никакого отношения к обсуждаемой изначально теме.
Вы уводите обсуждение в сторону, придираетесь к мелочам, игнорируете предложение реализовать обработку ошибок при захвате ресурсов с помощью RAII без исключений. Мне трудно представить, чтобы при этом вами двигало стремление к поиску истины.
Вы уже второй раз игнорируете второй пример с автоуказателем. У которого в конструкторе не может быть ошибок.
Что это меняет? Вернемся снова к аналогии с полиномами 8й степени. Вы можете привести бесконечное множество таких полиномов, корни которых можно найти аналитически. Но это не отменит тот факт, что в общем случае корни таких полиномов найти аналитически невозможно.
Вы можете приводить сколько угодно примеров таких ресурсов, при захвате которых не может возникнуть отказ. Но это не отменяет того, что существуют ресурсы, при захвате которых отказ возникнуть может.
С чего Вы взяли? Он — создан, а вот инициализирован он до конца (в его, объекта семантике) — это нужно у него узнать.
В языке C++ объект считается инициализированным после того, как завершил работу его конструктор. Разумеется, программист может обойти этот принцип, но концепция RAII подразумевает его строгое соблюдение.
Или, как Вы настаиваете, ловить исключение:… Мне вариант с исключениями не нравится громоздкостью.
Вы лукавите насчет громоздкости. Возможно, это свидетельствует об отсутствии у вас понимания эффективных способов использования исключений в C++. Прочитайте еще раз пример реализации RaiiFile с исключениями, который я привел выше, и укажите, где там находится громоздкий код.
Плюс Вы же сами упомянули, что исключения — «тяжелый» механизм.
Что поделаешь, это плата за удобство RAII. Не нравится «тяжесть» — вы всегда вольны отказаться от RAII.
Но не вижу причин делать тот или иной механизм обработки ошибок неотъемлемым признаком RAII.
В языке C++ это неотъемлемый признак RAII так же, как и деструкторы. Вы с тем же успехом могли бы доказывать, что деструкторы C++ не являются неотъемлемым признаком RAII.
Я настаиваю, что именно это и есть суть RAII. А не принцип проверки ошибок инициализации.
Оба принципа являются необходимыми для RAII в C++. Отказ от одного из них — это как лететь с одним крылом.
Вы сами упоминали, что исключения — это не единственный способ сообщить об ошибке.
Укажите пожалуйста иной способ сообщить об ошибке в конструкторе в C++ так, чтобы компилятор понял, что это именно сообщение об ошибке, и предоставил соответствующую поддержку. Аналогично, деструктор — это не единственное место, где можно разместить код освобождения ресурсов. Что тогда — не считать освобождение ресурсов в деструкторе неотъемлемой частью RAII?
Во-вторых, никакой «автоматической проверки ошибок» исключениями — нет. Программист всё-равно должен написать код проверки.
А какое же тогда есть автоматическое, как вы сказали, освобождение ресурсов с помощью деструкторов? Программист все равно должен писать код освобождения (в деструкторе).
Но по Вашему — не в месте возникновения ошибки, а в блоке catch.
В блоке catch пишется не код проверки, а код обработки ошибок. И то не весь. Часть его пишется в деструкторах. Код проверки же пишется в конструкторе. Посмотрите еще раз приведенный выше пример с RaiiFile.
Ну, как я уже писал, это дело вкуса и к RAII не имеет отношения.
Я уже аргументировал сообщением выше, почему это ваше мнение ошибочно.
Единственное что однозначно характеризует RAII — это работа деструктора.
Вы указали только один из важных механизмов RAII, но упорно отрицаете второй. Полагаю, в этом ваше заблуждение. Без исключений на C++ невозможно полноценно реализовать парадигму RAII так же, как и без деструкторов.
:)
Мы досконально, как я вижу, выяснили позиции друг друга.
Каждый остался при своём мнении, которое однако не мешает никому из нас использовать принцип RAII по своему. Благо он это позволяет.
int do_or_fail(void)
{
FILE *f1, *f2, *f3;
int retval = 0;
if(f1=fopen(«aaa.txt»,«r»)) {
if(f2=fopen(«bbb.txt»,«r»)) {
if(f3=fopen(«ccc.txt»,«r»)) {
/*… do something with the files… */
retval = 1;
fclose(f3);
}
fclose(f2);
}
fclose(f1);
}
return retval;
}
Что тут дублируется?
Причем это не обязательно должны быть файлы, это могут быть любые другие ресурсы, у которых подобная модель захвата с возможностью отказа. Память, например.
Но универсального ответа на ваш вопрос «как» — я дать не могу.
Это нужно разбираться в каждом конкретном проекте.
Ну и, повторю, наверное есть алгоритмы, где без goto или некуда или замена будет гораздо корявее, чем вариант с goto.
Но я с такими за 20 лет — не встречался.
Я с таким за 3 года работы часто сталкивался, что в элементарных случаях пишут вот такую портянку, и говорят что «иначе не сделаешь», а в реальности надо было только немного подумать. Простите если кого-то сейчас обидел. Я всего лишь молодой и глупый питонист.
vector<FILE*> files;
vector<string> names;
vector<bool> success;
// ресайз, заполнение имён файлов
...
bool group_success = true;
for(int i = 0; i < N; i++){
success[i] = (file[i] = fopen(names[i].c_str(), "r")) == NULL;
if(!success[i]){
group_success = false;
}
}
if(group_success){
// any actions with files
}
for(int i = 0; i < N; i++){
if(success[i]){
fclose(files[i]);
}
}
Можно и эту проблему решить, конечно. Создать, к примеру, функции-адаптеры. Для большого числа ресурсов это, наверно, хорошее решение. Но для среднего числа (3-10) — это стрельба из пушки по воробьям. Логика одной функции оказывается размазана на несколько функций, появляются циклы и дополнительные переменные. Для восприятия программы все это, на мой взгляд, тяжелее, чем конструкция с goto.
FILE *f1 = NULL, *f2 = NULL, *f3 = NULL;
int retval = 0;
do
{
if(!(f1=fopen(«aaa.txt»,«r»)))
break;
if(!(f2=fopen(«bbb.txt»,«r»)))
break;
if(!(f3=fopen(«ccc.txt»,«r»)))
break;
/*… do something with the files… */
retval = 1;
} while(FALSE);
if(!retval)
{
if (f1) fclose(f1);
if (f2) fclose(f2);
if (f3) fclose(f3);
}
Причем блок отката обычно выносится в отдельную функцию, которая позже вызывается как деструктор (например, если действия с файлами происходят не только в контексте вызова функции).
Ну и приведенная вами программа имеет следующие недостатки: цикл-который-не-цикл, лишние проверки («if(f1) fclose(f1);»). Не всякий ресурс допускает такую простую проверку на предмет существования. Для тех ресурсов, которые нельзя так проверить, придется заводить отдельные логические переменные.
В общем, goto в данном случае красивее и эффективнее. И приведенный мной паттерн — это не мое изобретение (хотя я его в свое время независимо изобрел), а классический пример-исключение, показывающий, что есть случаи, где применение goto оправдано.
А в целом вы правы, это попытка не использовать goto там где он подходит лучше.
Более адекватно код выглядит, если учесть, что описатели нужно закрывать не только здесь на откате при проблемах, но и при очистке объекта.
По-моему это неоптимальное решение. Если мы снова взглянем на RAII в C++ — то он выглядит примерно так:
class ResourceSet
{
private:
Resource a;
Resource b;
Resource c;
public:
ResourceSet(): a(), b(), c() {}
}
При создании объекта типа ResourceSet его конструктор поочередно захватывает ресурсы a, b и c. Если какой-либо из этих ресурсов недоступен — то соответствующий конструктор бросает исключение, и тогда создание объекта ResourceSet прерывается преждевременно. Исключение летит дальше вверх. А поскольку объект ResourceSet не был создан до конца (он считается созданным до конца после того, как будут созданы все объекты-члены и завершено исполнение тела конструктора) — то его деструктор не вызывается. Вызываются только деструкторы тех членов, которые уже были созданы на момент генерации исключения.
Соответственно, при уничтожении объекта ResourceSet() деструкторы членов вызываются безусловно, так как гарантированно известно, что все члены класса были успешно созданы.
Чтобы реализовать это на C, нужно иметь функцию, реализующую конструктор. Эта функция будет завершаться либо успешно — и тогда известно, что все ресурсы, которые она должна была захватить, захвачены; либо неуспешно — и тогда известно, что никаких ресурсов не захвачено, и вызывать «деструктор» не нужно. В таком случае в функции, реализующей концепцию деструктора, можно не проверять каждый ресурс, был ли он на самом деле захвачен.
В каком же состоянии окажутся ресурсы программы в результате goto — предсказать трудно.
Т.о. goto, точнее его положение в языке поднимает Си на уровень именно что Настоящего Языка, который как известно делает население — народом.
<пыыхххх....>
А это — явное разжигание и призыв к насилию
http://s670.photobucket.com/user/DeathLoveCrymo/media/see-computers-are-racist.jpg.html
На кол!
— Ещё бы — я там три года прожил!
И чтобы Google Translate мог переводить C на Java / C++ / PHP / JS и прочие диалекты малых народностей.
Да как бы в этих документов не появилось еще больше способов выстрелить себе в ногу...
Сегодня, 26 апреля 2016 г., арбитражный суд Орловской области должен был решить вопрос, является ли язык программирования C иностранным языком.
Эхо Чернобыля?
А если я сконструирую некий искусственный язык, в котором обыденные слова или некоторые внешне бессмысленные наборы символов будут иметь оскорбительное значение, а потом опубликую рекламное объявление на таком языке?
В какой момент объявление станет запрещенным? Сразу — или после того, как я опубликую словарь такого языка?
Не понимаю, как можно приравнять язык программирования к языку на котором разговаривают?
Вы видели людей, которые разговаривают на языке С?
if (nuzhna_rabota && esty_navyk) {
goto rabotay;
}
Только момент не понял: через двое суток после собеседования сценарий падает?
Assert.IsTrue(devExpress.Salary.IsNice)
Assert.IsTrue((DateTime.Now - visitTime) < new DateTime(0,0,0,2,0,0));
вычитание DateTime-ов даёт TimeSpan, который не сравнивается с DateTime.
Скорее всего специально добавили чтобы проверить кандидатов на внимательность :)
Английскую фразу обернули в Си-подобную конструкцию, теперь троллят несчастных провинциальных судей :-)
Реклама на иностранном языке, с чем спорим? :-)
Из ФЗ: «объект рекламирования — товар, средства индивидуализации юридического лица и (или) товара, изготовитель или продавец товара, результаты интеллектуальной деятельности либо мероприятие (в том числе спортивное соревнование, концерт, конкурс, фестиваль, основанные на риске игры, пари), на привлечение внимания к которым направлена реклама».
Таким образом, закон не содержит отсылки к вакансиям. Практика, как правило, такие объявления рекламой не считает, но есть ряд оговорок, к примеру, продукты/услуги компании упоминать в вакансии не стоит. Или если идет объявление о вакансии от трудового агенства — тогда это реклама.
В русском языке могут использоваться слова из других языков, но от этого фраза на русском языке не перестает оставаться таковой. Аналогично, выражение на языке C может использовать идентификаторы из любого языка с латинским алфавитом, но от этого оно все равно не перестанет оставаться на языке C
if (nuzhna_rabota && est_umenie) {
хотя…
если твойдед писал на С, отец писал на С и ты пишешь на С, то что-то в этом есть
Печалька. Вот бы всех расстрелять и заменить программой. Главное Сивиллой не называть и может все получится.
другой никогда не видел сишного синтаксиса.А вы считаете, каждый чиновник должен уметь C?
Ну а в 2016 году не то что не знать, а и просто не видеть ни разу синтаксиса языков программирования это уже даже не смешно. Зато, могу поспорить, 9 из 10 чинуш заходят во вконтактики и вообще хоть чуть-чуть пользуются компьютерами.
Раньше считалось что учить детей в школах делать киянки и ложки это достаточно. Тогда не было компьютеров. Но вот в 2016 почему-то даже учителя информатики в школах не знают как работает компьютер и учат как ходить на яндекс.
Короче говоря, с прогрессом в этих странах сейчас совсем чуть-чуть малость адовая жопа. От начала (обучение детей) и до конца (любой начальник любой государственной конторы).
Ну а в 2016 году не то что не знать, а и просто не видеть ни разу синтаксиса языков программирования это уже даже не смешно.Ну почему бы тогда не требовать с поваров знания ядерной физики? Принцип тот же. Как ниже подсказали, для подобных случаев существуют эксперты и экспертизы.
P. S. Компьютерная грамотность != знание синтаксиса каких-то там языков программирования.
Никто не требует грамотности или знания синтаксиса. Это было бы крайностью.
В общем риторика от крайностей считается грязной и к использованию не рекомендуется вот уже почти 2000 лет.
Ни одного молодого и образованного человека
Жизненного опыта мало. Чтобы руководить сложной системой, нужен опыт, который приобретается с годами. Иногда молодые (до 30) люди попадают во власть; если поискать, можно найти такие случаи. Но много ли вы знаете таких случаев, чтобы такой молодой властитель мудро руководил тем, что ему дали в управление?
все они — пережиток СССР
Вам не нравится СССР? Но ничего другого не было на территории современной РФ до 1992г. Все, кто родился на территории современной РФ до этой даты, не могут быть ничем иным, как «пережитком СССР». Вы предлагаете всех расстрелять:
Вот бы всех расстрелять
Но не за это ли ругают СССР, что, дескать, репрессии? Сами того не замечая, вы предлагаете совершать то, в чем обвиняете «совков».
Видать потому что разумные люди не так рвутся к этой дурацкой официальной власти
Погодите немного. Произойдет очередная смена поколений, и среди ваших сверстников начнется грызня не на жизнь, а на смерть, за участие в «дурацкой официальной власти».
____
Далеко ходить не надо:
Никифоров Николай Анатольевич, Министр связи и массовых коммуникаций Российской Федерации, родился: 24 июня 1982 (сейчас 33 года), 21 мая 2012 года указом Президента России Н. А. Никифоров был назначен министром — то есть 30 ему еще не было, а уже министр.
И да, руководитель из него еще тот…
Это они ещё AppleScript не видели:
tell application "Finder" to get POSIX path of (target of front Finder window as text)
В общем я хотел бы видеть объявление, которое покрывает все случаи без ложных срататываний. Собственно потому goto и является лишним и неправильным, вот для этого и нужна правильная конструкция с условиями. Ну или хотя бы правильно объявить переменные, раз уж так им хочется goto использовать.
Если вам кажется что вы понимаете смысл этой фразы то вам это просто кажется.
работа на сторк.ру?
«Гражданский процессуальный кодекс Российской Федерации» от 14.11.2002 N 138-ФЗ (ред. от 30.12.2015) (с изм. и доп., вступ. в силу с 01.01.2016)
Статья 9. Язык гражданского судопроизводства
2. Лицам, участвующим в деле и не владеющим языком, на котором ведется гражданское судопроизводство, разъясняется и обеспечивается право давать объяснения, заключения, выступать, заявлять ходатайства, подавать жалобы на родном языке или на любом свободно избранном языке общения, а также пользоваться услугами переводчика.
goto Stork;
}
есть два человека: один знает английский, но не знает С и других языков программирования; другой знает С, но даже поверхностно не знаком с английским, вот вообще ни одного слова не знает. Кто из них поймет значение этого объявления?
Каким образом человек может знать си, но не знать английского? Тем более ни одного слова, если там все операторы представляют собой чистейший английский. Со стандартами именования переменных и прочего. И практически все конструкции написанные логичным англофоном можно прочитать как слегка кастрированный, но всё равно английский? Что-то выше anykey в современном мире для программиста начинается с английского, потому что там содержится основная прорва информации, в том числе новой, пока ещё актуальной. Именно там можно найти пути карьерного роста и более высокая вероятность встретить людей-гуру, при чём без разницы, на какой ступени развития сейчас находится соискатель.
Каким образом человек может знать си, но не знать английского?
Жил в пещере, и была у него одна книжка «С для чайников» на русском.
Я самолично (на курсах английского) видел несколько программистов, которые пользовались англоязычными терминами, названиями операторов, даже не задумываясь о «нормальном» значении слов, они их запоминали как имена.
Но это все не важно. Это мысленный эксперимент, в этом его суть.
Я самолично (на курсах английского) видел несколько программистов, которые пользовались англоязычными терминами, названиями операторов, даже не задумываясь о «нормальном» значении слов, они их запоминали как имена.
Оно запоминается не именами, а как раз «образом» из ЯП. Как то развлекался анализом своих фраз по работе: англицизмов невероятно много и все они служат для подчеркивания рабочих моментов. В итоге получается, что Дата и Данные — это разные слова с точки зрения смысловой нагрузки, а в английском оно вообще может иметь смысл только применительно к конкретному случаю. Практикуюсь в английском и приходится вычищать свою речь от Delete вместо Remove, Data вместо Information и т.п. Друг дико ржет над тем, как я порой фразы строю, а оно уже в подкорку забито.
Есть предположение, что корректнее этот текст должен было выглядеть примерно так:
if ( you( need_job && have_skills ) ) {
goto Stork;
}
Не говоря уже о том, что этот код валиден на целом семействе языков с похожим синтаксисом (goto не выпиливается почти нигде, оператор ветвления, переменные, условный оператор AND и блоки кода — стандарт для высокоуровневых языков). А необходимость понимать это без перевода напрямую содержится в переменной have_skills...
if ( you( NEED_JOB && HAVE_SKILLS ) ) {
goto Stork;
}
if ($there is 'goto' in $companyCode)
throw $this->company['away'];
Что они тогда скажут про рожицы и какашки? Что это язык?
Ритчи, Томпсон и Керниган — наши пророки. Страуструп — вероотступник, лживый мессия. Bell Labs — наша Мекка. И сейчас — 44-й год от основания мира. )
Русский язык — это естественный язык, а Си — язык формальный, но нифига не иностранный. Если ФАС не понимает разницы между этими двумя понятиями, то это их проблема, а проблема суда – разобраться, для этого достаточно пригласить нормального лингвиста который разжуёт судье разницу между этими двумя понятиями.
Я думаю, что смогу сейчас найти штук 5 реклам с математическими формулами/кванторами, к которым ФАС не имеет никаких претензий по поводу необходимости перевода формул с математического языка на русский.
Интересно, а какие аргументы можно привести в защиту компании? Что-то я ни одного не могу придумать.
(Из закона о рекламе)
В данном случае это информация адресованная определённому кругу лиц: программистам.
interview(&Stork);
}
А вот это мне понравилось:
Специалист Ершов М.Н. суду пояснил размещенное на рекламном щите изображение
не является текстом на каком-либо иностранном языке, а копирует часть авторского
программного продукта, написанного на языке программирования «С++».
Это был всего лишь кусок кода на C++ из некой программы (по мнению специалиста Ершова)
Или использованные на картине иностранные слова тоже надо переводить?
finnally {TakieDela();}
Было бы интересно почитать коментарии о судебном заседании. Ведь наверняка там были какие-нибудь перлы как с одной так и с другой стороны.
Ну что же, сегодня 27.05.2016 состоялось финальное заседание арбитражного суда Орловской области, на котором судья не согласилась с претензиями ФАС относительно нашего плаката с объявлением на языке программирования ))
Таким образом суд первой инстанции мы выиграли, но еще вчера представитель ФАС, открыто заявила, что будут обжаловать решение, и готовы идти до Высшего арбитражного суда.
Я так понимаю, у них (ФАС) денег куры не клюют, и они могут позволить себе такие расходы? Тогда мы тоже готовы продолжать ликбез и далее, если этого потребует ситуация
Программисты на C — самый большой разделённый народ в мире?