Várias explicações. O primeiro é geral, o segundo é específico para macros do pré-processador C com parâmetros:
Controle de fluxo
Eu já vi isso usado no código C simples. Basicamente, é uma versão mais segura do goto, pois você pode sair dele e toda a memória é limpa corretamente.
Por que algo goto
parecido seria bom? Bem, se você tiver o código, onde praticamente todas as linhas pode retornar um erro, mas você precisa para reagir a todos eles da mesma forma (por exemplo, pela entrega o erro com o seu interlocutor após limpeza), é geralmente mais legível para evitar um if( error ) { /* cleanup and error string generation and return here */ }
como evita a duplicação do código de limpeza.
No entanto, em C ++ você tem exceções + RAII exatamente para esse fim, então eu consideraria o estilo de codificação ruim.
Verificação de ponto e vírgula
Se você esquecer o ponto-e-vírgula após uma chamada de macro do tipo função, os argumentos poderão se contrair de maneira indesejada e compilar na sintaxe válida. Imagine a macro
#define PRINT_IF_DEBUGMODE_ON(msg) if( gDebugModeOn ) printf("foo");
Isso é acidentalmente chamado como
if( foo )
PRINT_IF_DEBUGMODE_ON("Hullo\n")
else
doSomethingElse();
O "else" será considerado associado ao gDebugModeOn
, portanto, quando foo
for false
, ocorrerá o reverso exato do que foi planejado.
Fornecendo um escopo para variáveis temporárias.
Como o do / while possui chaves, variáveis temporárias têm um escopo claramente definido, das quais não podem escapar.
Evitando avisos de "ponto e vírgula possivelmente indesejados"
Algumas macros são ativadas apenas nas compilações de depuração. Você os define como:
#if DEBUG
#define DBG_PRINT_NUM(n) printf("%d\n",n);
#else
#define DBG_PRINT_NUM(n)
#endif
Agora, se você usar isso em uma versão compilada dentro de um condicional, ele compila para
if( foo )
;
Muitos compiladores veem isso como o mesmo que
if( foo );
O que geralmente é escrito acidentalmente. Então você recebe um aviso. O do {} while (false) oculta isso do compilador e é aceito por ele como uma indicação de que você realmente não quer fazer nada aqui.
Evitando a captura de linhas por condicionais
Macro do exemplo anterior:
if( foo )
DBG_PRINT_NUM(42)
doSomething();
Agora, em uma compilação de depuração, como também incluímos habitualmente o ponto-e-vírgula, isso compila perfeitamente. No entanto, na versão compilada, isso de repente se transforma em:
if( foo )
doSomething();
Ou mais claramente formatado
if( foo )
doSomething();
O que não é exatamente o que foi planejado. Adicionar um {{}} while (false) ao redor da macro transforma o ponto-e-vírgula ausente em um erro de compilação.
O que isso significa para o OP?
Em geral, você deseja usar exceções no C ++ para tratamento de erros e modelos em vez de macros. No entanto, no caso muito raro em que você ainda precise de macros (por exemplo, ao gerar nomes de classe usando colagem de token) ou esteja restrito ao C simples, esse é um padrão útil.