Зачем нужен цикл do-while для этого случая [duplicate]

Скажите, что у вас есть DataFrame:

>>> df = pd.DataFrame([['hello', 'hello world'], ['abcd', 'defg']], columns=['a','b'])
>>> df
       a            b
0  hello  hello world
1   abcd         defg

Вы всегда можете использовать оператор in в выражении лямбда для создания вашего фильтра.

>>> df.apply(lambda x: x['a'] in x['b'], axis=1)
0     True
1    False
dtype: bool

Трюк здесь состоит в том, чтобы использовать опцию axis=1 в apply для передачи элементов в функцию лямбда по строке, в отличие от столбца по столбцу.

115
задан Gordon Gustafson 22 February 2010 в 23:18
поделиться

24 ответа

Вы можете break выйти из do{...}while(false).

156
ответ дан Thomas Eding 21 August 2018 в 19:01
поделиться
  • 1
    +1, потому что это, вероятно, цель кода, но делать что-то подобное - это просто идиотски замаскированный переход. Если вы считаете, что goto является правильным инструментом для работы, тогда вам нужно просто использовать # $ (* # @ goto. – dsimcha 22 February 2010 в 21:55
  • 2
    Это нечто большее, чем замаскированный переход. Это ограниченный (структурированный) переход. – Thomas Eding 22 February 2010 в 21:56
  • 3
    Каким образом это «ограниченный»? Только прыжки вперед вряд ли являются «ограничением». Goto - это goto, и одевание одного, чтобы он выглядел так, будто это не одно, хуже, чем просто использовать goto в первую очередь. – Anon. 22 February 2010 в 21:58
  • 4
    @Anon .: Прыжки вперед - это ограничение на goto, и выпрыгивание, безусловно, является ограничением. Реальная проблема с gotos - это код спагетти, и это очень важно для форварда и выхода. – David Thornley 22 February 2010 в 22:01
  • 5

Это изобретательный способ эмулировать GOTO, поскольку эти два практически идентичны:

// NOTE: This is discouraged!
do {
    if (someCondition) break;
    // some code be here
} while (false);
// more code be here

и:

// NOTE: This is discouraged, too!
if (someCondition) goto marker;
// some code be here
marker:
// more code be here

С другой стороны, обе эти должно действительно выполняться с помощью if s:

if (!someCondition) {
    // some code be here
}
// more code be here

Хотя вложенность может стать немного уродливой, если вы просто превратите длинную строку forward- GOTO s в вложенные if s. Настоящий ответ - правильный рефакторинг, хотя и не имитирующий архаичные языковые конструкции.

Если вы отчаянно пытались транслировать алгоритм с GOTO s в нем, вы могли бы, вероятно, сделать это с этой идиомой. Это, конечно, нестандартный и хороший показатель того, что вы не придерживаетесь близко ожидаемых идиом языка.

Я не знаю ни одного языка C, где do / while является идиоматическое решение для чего угодно.

Вероятно, вы могли бы реорганизовать весь беспорядок во что-то более разумное, чтобы сделать его более идиоматичным и более читаемым.

0
ответ дан Alan Plum 21 August 2018 в 19:01
поделиться
  • 1
  • 2
    Он работает неопределенное количество раз, если у вас есть условный оператор continue в конце, как я показал. В undefined я просто хочу сказать, что вы не знаете, работает ли он более одного раза, если вы не можете предсказать, будут ли условия выполняться на определенной итерации. Без каких-либо continue s в нем do..while(false) будет выполняться один раз, но также без каких-либо break s в нем while(true) будет работать вечно, поэтому «поведение по умолчанию» на самом деле не имеет отношения к пониманию того, что может сделать с помощью циклов. – Alan Plum 23 February 2010 в 12:32
  • 3
    Это полезно, если вы определяете макрос, который содержит несколько операторов. Если вы завернете их в do / while (false), вы можете использовать макрос в операторе if / else, как и любой другой вызов функции. см. noveltheory.com/TechPapers/while.htm для объяснения – John Paquin 25 April 2012 в 21:07
  • 4
    – Ben Voigt 2 May 2012 в 05:40
  • 5
    -1, два первых утверждения не идентичны по причинам, которые @BenVoigt указывает. – cmh 14 August 2013 в 11:59

Это просто: Очевидно, вы можете выпрыгнуть из фальшивого цикла в любое время, используя инструкцию break. Кроме того, блок do представляет собой отдельную область (которая также может быть достигнута только с помощью { ... }).

В такой ситуации может быть лучше использовать RAII (объекты автоматически разрушаются правильно когда функция заканчивается). Другая аналогичная конструкция - использование goto - да, я знаю, что это зло , но его можно использовать для общего кода очистки следующим образом:

<return-type> function(<params>)
{
 <initialization>

 <main code for function using "goto error;" if something goes wrong>

 <tidy-up in success case & return>

 error:

 <commmon tidy-up actions for error case & return error code or throw exception>
}

(As В стороне: конструктор do-while-false используется в Lua, чтобы найти недостающую инструкцию continue.)

2
ответ дан AndiDog 21 August 2018 в 19:01
поделиться

Этот трюк используется программистами, которые слишком застенчивы, чтобы использовать явный goto в своем коде. Автор вышеуказанного кода хотел иметь возможность перейти непосредственно к точке «очистка и возврат» из середины кода. Но они не хотели использовать метку и явные goto. Вместо этого они могут использовать break внутри тела вышеупомянутого «поддельного» цикла для достижения того же эффекта.

7
ответ дан AnT 21 August 2018 в 19:01
поделиться

Многие люди отмечают, что он часто используется с перерывом как неудобный способ написания «goto». Это, вероятно, так, если оно написано непосредственно в функции.

В макросе OTOH, do {something; } while (false) - это удобный способ FORCE с запятой после вызова макроса, абсолютно никакой другой токен не может следовать.

И еще одна возможность заключается в том, что там либо был цикл, либо ожидалась итерация который должен быть добавлен в будущем (например, в тестовой версии, итерация не нужна для прохождения тестов, но логически было бы целесообразно зацикливать там, если функция должна быть несколько более общей, чем требуется в настоящее время)

105
ответ дан Ben Voigt 21 August 2018 в 19:01
поделиться
  • 1
    +1 для упоминания полезности этого в макросах; Я удивлен, что никто не упоминал об этом! – Nick Meyer 22 February 2010 в 22:28
  • 2
    Да, макроэлемент на самом деле является вполне допустимым использованием этого. Конечно, внешние макросы, это просто глупо ...;) – jalf 22 February 2010 в 22:40
  • 3
    Это не сложно, это полезно, потому что это Scoped goto - это означает, что любые переменные, которые вы объявляете в цикле do, уничтожаются, а goto этого не делает. – Paul Betts 23 February 2010 в 00:06
  • 4
    @Paul: Ничто не мешает вам добавлять фигурные скобки вокруг множества операторов, чтобы заставить это поведение с goto. – erikkallen 23 February 2010 в 12:57
  • 5
    @Paul: goto из блока наиболее определенно вызывает локальные переменные, которые будут уничтожены на C ++, так же, как и break. А в переменных C не реально уничтожены, их пространство стека просто исправлено. – Ben Voigt 23 February 2010 в 17:00

Я видел такой код, поэтому вы можете использовать break как goto.

11
ответ дан Brian Young 21 August 2018 в 19:01
поделиться

Я видел, что он использовался как полезный шаблон, когда есть много потенциальных точек выхода для функции, но тот же код очистки всегда требуется независимо от того, как функция выходит.

Это может сделать утомительно, если / else - если дерево намного легче читать, просто нужно ломаться всякий раз, когда достигается точка выхода, а остальная часть логической строки впоследствии.

Этот шаблон также полезен на языках, которые У меня есть инструкция goto. Возможно, именно там исходный программист узнал образец.

19
ответ дан Cameron 21 August 2018 в 19:01
поделиться
  • 1
    Тогда просто используйте честную, прямолинейную гото вместо тонко замаскированного пере. – dsimcha 22 February 2010 в 21:56
  • 2
    Мне нравится этот путь лучше. Он легко читается и не несет клейма goto. – Cameron 22 February 2010 в 21:57
  • 3
    gotos легко читаются, если их использовать экономно и локально. Они получили от них стигму, когда они были основной формой контроля потока и прыгали через сотни линий. – dsimcha 22 February 2010 в 21:59
  • 4
    Не использовать goto из-за «стигмы». является верным признаком грубо-культового программирования. – Anon. 22 February 2010 в 21:59
  • 5
    Не говоря уже о том, что масса кода очистки - плохой запах. Это C ++, код очистки обычно должен быть в деструкторах, вызываемых во время обработки RAII. – David Thornley 22 February 2010 в 22:02

В дополнение к уже упомянутым «примерам goto», do ... while (0) idiom иногда используется в определении макроса, чтобы обеспечить скобки в определении и все еще иметь работу компилятора с добавлением полуколонки к конец макросообщения.

http://groups.google.com/group/comp.soft-sys.ace/browse_thread/thread/52f670f1292f30a4?tvc=2&q=while+ (0)

1
ответ дан Dan 21 August 2018 в 19:01
поделиться

Некоторые кодеры предпочитают иметь только один выход / возврат из своих функций. Использование манекена do {....} while (false); позволяет вам «вырваться» из фиктивной петли, как только вы закончите, и все еще имеете один возврат.

Я java-кодер, поэтому мой пример будет похож на

import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class p45
{
    static List<String> cakeNames = Arrays.asList("schwarzwald torte", "princess", "icecream");
    static Set<Integer> forbidden = Stream.of(0, 2).collect(Collectors.toSet());

    public static  void main(String[] argv)
    {
        for (int i = 0; i < 4; i++)
        {
            System.out.println(String.format("cake(%d)=\"%s\"", i, describeCake(i)));
        }
    }


    static String describeCake(int typeOfCake)
    {
        String result = "unknown";
        do {
            // ensure type of cake is valid
            if (typeOfCake < 0 || typeOfCake >= cakeNames.size()) break;

            if (forbidden.contains(typeOfCake)) {
                result = "not for you!!";
                break;
            }

            result = cakeNames.get(typeOfCake);
        } while (false);
        return result;
    }
}
0
ответ дан David Young 21 August 2018 в 19:01
поделиться

Это очень распространенная практика. В C. Я пытаюсь думать об этом так, как будто вы хотите лгать себе таким образом: «Я не использую goto». Думая об этом, не было бы ничего плохого в использовании goto, используемого аналогичным образом. Фактически это также уменьшит уровень отступов.

Тем не менее, я заметил, что очень часто эта петля do..while имеет тенденцию к росту. И затем они получают внутри if s и else, что делает код на самом деле не очень читаемым, не говоря уже о проверке.

Те, кто do..while, как правило, предназначены для очистки . По возможности я предпочел бы использовать RAII и вернуться раньше из функции short . С другой стороны, C не предоставляет вам столько удобств, как C ++, что делает do..while одним из лучших подходов к очистке.

7
ответ дан Dmitry 21 August 2018 в 19:01
поделиться

Это забавно. Вероятно, в петле есть перерывы, как говорили другие. Я бы сделал это так:

while(true)
{
   <main code for function>
   break; // at the end.
}
-1
ответ дан fastcodejava 21 August 2018 в 19:01
поделиться
  • 1
    С потенциалом петли навсегда? do..while(false) всегда выходит, while(true) находится на рискованной стороне. – Dmitry 22 February 2010 в 22:44
  • 2
    while(true) - правильная идиома на большинстве языков. Вы часто найдете его в графических приложениях в качестве основного цикла программы. Поскольку вы в основном предполагаете, что программа не должна умирать, пока не будет сказано, что это do..while(false) вызовет всевозможные надуманные логики. Этот подход может быть более рискованным из перфекционистского POV, но он семантически проще и, следовательно, менее подвержен ошибкам для программистов-программистов (извините, Скайнет). – Alan Plum 22 February 2010 в 23:30
  • 3
    @dmitry do{...}while(false) точно такой же, как while(true){ .. break;} – N 1.1 10 March 2010 в 10:18
  • 4
    @ N1.1: Не при наличии continue, они не совпадают. – Ben Voigt 2 May 2012 в 05:42

Возможно, он используется так, чтобы break можно было использовать внутри, чтобы прервать выполнение дополнительного кода в любой точке:

do {
    if (!condition1) break;
    some_code;
    if (!condition2) break;
    some_further_code;
    // …
} while(false);
2
ответ дан Gumbo 21 August 2018 в 19:01
поделиться
  • 1
    Это похоже на попытку избежать использования goto только потому, что кто-то слышал, что это «плохо». – Anon. 22 February 2010 в 21:55
  • 2
    Возможно, но C ++ имеет исключения именно по этой причине. – T.E.D. 22 February 2010 в 22:25

Перерыв как goto, вероятно, является ответом, но я выдвину еще одну идею.

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

Помните, что в последнее время C ++ допускает {...} в любом месте, это не всегда так.

23
ответ дан Hogan 21 August 2018 в 19:01
поделиться
  • 1
    В этом случае он мог использовать только фигурные скобки. – Nemanja Trifunovic 22 February 2010 в 22:16
  • 2
    @Nemanja, вы были бы удивлены тем, как многие разработчики этого не знают, и попробуйте что-то связанное с тем, что предлагает Hogan – Polaris878 22 February 2010 в 22:24
  • 3
  • 4
    @Nemanja: Я не знаю точно, когда, но я уверен, что {...} где-то более современная разработка в C ++ (помните, что первый C ++, который я использовал, был реализован с предварительным процессором, и это не позволяло это современное использование .) Возможно, автор был просто старой школой. – Hogan 22 February 2010 в 23:21
  • 5
    Когда это не допускало брекеты повсюду? Я начал программировать, как 15 лет назад, и тогда это было разрешено (как в моем учебнике, так и в каждом компиляторе, который я пробовал). – erikkallen 23 February 2010 в 12:59

Я думаю, что это делается для использования операторов break или continue. Некоторая логика кода «goto».

2
ответ дан Ivan Nevostruev 21 August 2018 в 19:01
поделиться

Это просто извращение while, чтобы получить семантику goto tidy-up без использования слова goto.

Это плохая форма, потому что, когда вы используете другие петли внутри внешнего while, breaks становятся двусмысленными для читателя. «Предполагается ли это, что он должен выйти?» или это предназначено только для выхода из внутреннего цикла? »

10
ответ дан John Knoeller 21 August 2018 в 19:01
поделиться

Я работаю с Adobe InDesign SDK, а примеры InDesign SDK имеют почти каждую функцию, написанную так. Это связано с тем, что функция обычно очень длинная. Где вам нужно выполнить QueryInterface (...), чтобы получить что-либо из объектной модели приложения. Таким образом, обычно каждый QueryInterface следует за if, но не прошел хорошо, перерыв.

0
ответ дан Kugel 21 August 2018 в 19:01
поделиться

Многие уже заявили о сходстве между этой конструкцией и goto и выразили предпочтение goto. Возможно, фон этого человека включал среду, в которой goto's строго запрещалось правилами кодирования?

0
ответ дан Mark Ransom 21 August 2018 в 19:01
поделиться

Многие ответчики дали объяснение do{(...)break;}while(false). Я хотел бы дополнить эту картину еще одним примером реальной жизни.

В следующем коде мне пришлось установить перечислитель operation на основе адреса, на который указывает указатель data. Поскольку ящик коммутатора может использоваться только для скалярных типов, я сначала сделал это неэффективно

if (data == &array[o1])
    operation = O1;
else if (data == &array[o2])
    operation = O2;
else if (data == &array[on])
    operation = ON;

Log("operation:",operation);

Но поскольку Log () и остальная часть кода повторяются для любого выбранного значения операции, я блуждал, как чтобы пропустить остальные сравнения, когда адрес уже обнаружен. И вот здесь do{(...)break;}while(false) пригодится.

do {
    if (data == &array[o1]) {
        operation = O1;
        break;
    }
    if (data == &array[o2]) {
        operation = O2;
        break;
    }
    if (data == &array[on]) {
        operation = ON;
        break;
    }
} while (false);

Log("operation:",operation);

Можно задаться вопросом, почему он не мог сделать то же самое с break в выражении if, например:

if (data == &array[o1])
{
    operation = O1;
    break;
}
else if (...)

break взаимодействует исключительно с ближайшим замкнутым контуром или переключателем, будь то тип for, while или do .. while, поэтому, к сожалению, это не сработает.

2
ответ дан Matt Bucci 21 August 2018 в 19:01
поделиться

Другая причина, по которой я могу думать, заключается в том, что она украшает фигурные скобки , в то время как я верю в более новые стандартные фигуры C ++, голые скобки не в порядке (ISO C им не нравится). В противном случае, чтобы успокоить статический анализатор, например, lint.

Не знаете, почему вы хотите их, возможно, переменную область или преимущество с отладчиком.

См. Trivial Do While loop и Скобки хороши из C2.

Чтобы прояснить мою терминологию (которая, как я полагаю, следует за стандартным использованием):

Naked :

init();
...
{
c = NULL;
mkwidget(&c);
finishwidget(&c);
}
shutdown();

Пустые фигурные скобки (NOP):

{}

например

while (1)
   {}  /* Do nothing, endless loop */

Блок :

if (finished)
{
     closewindows(&windows);
     freememory(&cache);
}

, который станет

if (finished)
     closewindows(&windows);
freememory(&cache);

, если фигурные скобки будут удалены, что изменит поток выполнения, а не только область локальных переменных. Таким образом, не «автономный» или «голый».

Голые фигурные скобки или блок могут использоваться для обозначения любого раздела кода, который может быть потенциальным (встроенной) функцией, которую вы хотите отметить, но не рефактору в то время.

0
ответ дан mctylr 21 August 2018 в 19:01
поделиться
  • 1
    В самом деле? Это позор. Одной из немногих вещей, которые мне нравились в C, было то, что она позволяла вам объявлять новую вложенную область практически где угодно. – T.E.D. 22 February 2010 в 22:29
  • 2
    Голые скобки иногда полезны для устранения странных сбоев. См. blogs.msdn.com/oldnewthing/archive/2004/05/20/135841.aspx . – Brian 22 February 2010 в 23:29
  • 3
    В C ++ блок (т. Е. Ваши «голые фигурные скобки») можно использовать везде, где допускается один оператор. – Ben Voigt 2 May 2012 в 05:43
  • 4
    @BenVoigt Пустые фигурные скобки, то есть NOP отличается от «обнаженных брекетов». который представляет собой блок, добавленный вокруг линейной последовательности инструкций. Например. `printf (& quot; Hello & quot;); {putchar (','); putchar (0x20); } printf («мир!\n»); `где фигурные скобки являются не частью цикла или управления ветвью. – mctylr 10 May 2012 в 16:08
  • 5
    @mctylr: Я не говорил о пустых брекетах. – Ben Voigt 10 May 2012 в 20:55

Он похож на программиста C. В C ++ у автоматических переменных есть деструкторы, которые вы используете для очистки, поэтому перед возвратом не должно быть ничего необходимого. В C у вас не было этой RAII идиомы, поэтому, если у вас есть общий код очистки, вы либо goto, либо используете однократный цикл, как указано выше.

. Его главный недостаток по сравнению с идиомой C ++ заключается в том, что он не будет убирать, если в тело будет выброшено исключение. У C не было исключений, поэтому это не было проблемой, но это делает его плохой привычкой в ​​C ++.

6
ответ дан Pete Kirkham 21 August 2018 в 19:01
поделиться

Я думаю, что удобнее писать break вместо goto end. Вам даже не нужно придумывать имя для ярлыка, которое делает намерение более ясным: вы не хотите переходить на метку с определенным именем. Вы хотите выбраться отсюда.

Также, возможно, вам понадобятся брекеты. Итак, это версия do{...}while(false);:

do {
   // code
   if (condition) break; // or continue
   // more code
} while(false);

И так вы должны были бы выразить это, если хотите использовать goto:

{
   // code
   if (condition) goto end;
   // more code
}
end:

I думаю, смысл первой версии гораздо легче понять. Также легче писать, проще расширять, проще переводить на язык, который не поддерживает goto и т. Д.


Наиболее часто упоминаемая проблема использования break что это плохо замаскировано goto. Но на самом деле break имеет больше сходства с return: обе команды выпрыгивают из блока кода, который в значительной степени структурирован по сравнению с goto. Тем не менее обе команды позволяют нескольким точкам выхода в блоке кода, который иногда может сбивать с толку. В конце концов, я попытался бы найти наиболее четкое решение, независимо от того, что находится в конкретной ситуации.

9
ответ дан Robert 21 August 2018 в 19:01
поделиться
  • 1
    О, я только заметил, что я полностью не понял вопрос, прежде чем отвечать. Я думал, что речь идет об использовании do{ ... }while(false); в целом. Но на самом деле речь идет о том, чтобы использовать его для эмуляции какого-то try{ ... }finally{ ... }. – Robert 19 June 2012 в 14:14
  • 2
    Хорошее наблюдение параллели между перерывом и возвратом, а не goto. Согласитесь, что лучшее решение - лучшее. Во многих случаях, вероятно, яснее инкапсулировать такой код в свою собственную функцию, которая использует возврат, а не разрыв, а затем выполняет очистку в вызывающей функции. – persiflage 28 March 2018 в 15:04

Я согласен с большинством плакатов об использовании в качестве тонко замаскированного goto. Макросы также упоминаются как потенциальная мотивация для написания кода в стиле.

Я также видел эту конструкцию, используемую в смешанных средах C / C ++ как исключение бедных. «Do {} while (false)» с «break» можно использовать для перехода в конец блока кода, если в цикле будет встречено что-то, что обычно требует исключения.

Я также использовал эту конструкцию, используемую в магазинах, где применяется идеология «единственного возвращения на каждую функцию». Опять же, это вместо явного «goto», но мотивация заключается в том, чтобы избежать множественных точек возврата, а не «пропустить» код и продолжить фактическое выполнение внутри этой функции.

0
ответ дан Stan Graves 21 August 2018 в 19:01
поделиться

Сколько лет был автор?

Я спрашиваю, потому что однажды я наткнулся на какой-то код Fortran в реальном времени, который сделал это, еще в конце 80-х. Оказывается, это действительно хороший способ имитировать потоки на ОС, которые их не имеют. Вы просто помещаете всю программу (ваш планировщик) в цикл и называете свои «потоковые» подпрограммы «один за другим». Процедуры потоков сами по себе являются циклами, которые повторяются до тех пор, пока не произойдет один из нескольких условий (часто один из них является определенным количеством прошло время). Это «совместная многозадачность», так как отдельные потоки позволяют отказываться от процессора каждый раз, а затем, чтобы другие не истощались. Вы можете вставлять вызовы подпрограмм цикла для имитации приоритета потока полосы.

1
ответ дан T.E.D. 21 August 2018 в 19:01
поделиться

Несколько объяснений. Первый - общий, второй - для макросов препроцессора C с параметрами:

Управление потоком

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

Почему что-то goto -подобно быть хорошим? Ну, если у вас есть код, в котором почти каждая строка может возвращать ошибку, но вам нужно реагировать на все одинаково (например, передав ошибку вашему вызывающему абоненту после очистки), обычно более читаемо, чтобы избежать if( error ) { /* cleanup and error string generation and return here */ }, поскольку он избегает дублирования кода очистки.

Однако в C ++ у вас есть исключения + RAII для этой цели, поэтому я бы назвал это неправильным стилем кодирования.

Точка с запятой проверка

Если вы забыли точку с запятой после функционального вызова макроса, аргументы могут быть сжаты нежелательным образом и скомпилированы в действительный синтаксис. Представьте себе макрос

#define PRINT_IF_DEBUGMODE_ON(msg) if( gDebugModeOn ) printf("foo");

. Это случайно называется

if( foo )
    PRINT_IF_DEBUGMODE_ON("Hullo\n")
else
    doSomethingElse();

. «Else» будет считаться связанным с gDebugModeOn, поэтому, когда foo false, точный реверс того, что предназначалось, будет иметь место.

Предоставление области для временных переменных.

Так как do / while имеет фигурные скобки, временные переменные имеют четко определенные область действия, с которой они не могут убежать.

Избегание предупреждений «возможно нежелательной точки с запятой»

Некоторые макросы активируются только в отладочных сборках. Вы определяете их как:

#if DEBUG
#define DBG_PRINT_NUM(n) printf("%d\n",n);
#else
#define DBG_PRINT_NUM(n) 
#endif

Теперь, если вы используете это в сборке релизов внутри условного выражения, он компилируется в

if( foo )
    ;

. Многие компиляторы видят это как то же, что

if( foo );

, который часто записывается случайно. Поэтому вы получаете предупреждение. Do {} while (false) скрывает это от компилятора и принимается им как указание на то, что вы действительно ничего не хотите здесь делать.

Избегать захвата строк на conditionals

Макрос из предыдущего примера:

if( foo )
    DBG_PRINT_NUM(42)
doSomething();

Теперь, в сборке отладки, поскольку мы также обычно включаем точку с запятой, это компилируется просто отлично. Однако в релиз-сборке это внезапно превращается в:

if( foo )

doSomething();

Или более четко отформатировано

if( foo )
    doSomething();

Это совсем не то, что было предназначено. Добавление do {...} while (false) вокруг макроса превращает недостающую точку с запятой в ошибку компиляции.

Что это значит для OP?

В общем, вы хотите использовать исключения в C ++ для обработки ошибок и шаблоны вместо макросов. Однако в очень редком случае, когда вам все еще нужны макросы (например, при генерации имен классов с использованием вставки меток) или они ограничены равным C, это полезный шаблон.

2
ответ дан uliwitness 21 August 2018 в 19:01
поделиться
  • 1
    Что касается области обзора, вам не нужен петлевой аппарат; "неприкрашенный" блок является законным: x =1; y = 2; { int tmp = y; y = x; x = tmp; }. – chepner 24 August 2017 в 12:16
  • 2
    Незакрашенный блок не обеспечивает наличие отсутствующей точки с запятой, хотя это может иметь нежелательные побочные эффекты. Делать пока(); ТРЕБУЕТСЯ точку с запятой и, таким образом, Не приводит к тому, что следующие инструкции втягиваются в "if" если макрос ничего не определяет в сборке релиза, как мой пример выше. – uliwitness 6 September 2017 в 16:15
  • 3
    Нельзя ли этого избежать, просто предоставив лучшее определение для макроса? #define DBG_PRINT_NUM(n) {}. – chepner 6 September 2017 в 16:25
  • 4
    Нет, потому что {} - это полный оператор, то есть эквивалент «.». Поэтому, если вы пишете if(a) DBG_PRINT_NUM(n); else other();, он не будет компилироваться. Только if(a) {} else other(); или if(a) ; else other(); действительны, но if(a) {}; else other(); нет, потому что это делает «если», состоит из двух утверждений. – uliwitness 8 September 2017 в 13:23
  • 5
    Так я и забыл; Спасибо. – chepner 8 September 2017 в 13:25
Другие вопросы по тегам:

Похожие вопросы: