Significado de ios_base :: sync_with_stdio (false); cin.tie (NULL);

146

Qual é o significado de incluir

ios_base::sync_with_stdio(false);
cin.tie(NULL);

em programas C ++?

Nos meus testes, isso acelera o tempo de execução, mas há um caso de teste que eu deveria me preocupar em incluir isso?

As duas instruções sempre precisam estar juntas ou a primeira é suficiente, ou seja, é ignorar cin.tie(NULL)?

Além disso, é permitido usar comandos simultâneos de C e C ++ se seu valor tiver sido definido como false?

https://www.codechef.com/viewsolution/7316085

O código acima funcionou bem, até que eu usei scanf/printfem um programa C ++ com o valor como true. Nesse caso, ocorreu uma falha de segmentação. Qual poderia ser a explicação possível para isso?

Kshitij Kohli
fonte
Você realmente usou isso com false. Seu código diz isso ???
Suraj Jain

Respostas:

231

As duas chamadas têm significados diferentes que nada têm a ver com desempenho; o fato de acelerar o tempo de execução é (ou pode ser ) apenas um efeito colateral. Você deve entender o que cada um deles faz e não os incluir cegamente em todos os programas, porque eles parecem uma otimização.

ios_base::sync_with_stdio(false);

Isso desativa a sincronização entre os fluxos padrão C e C ++. Por padrão, todos os fluxos padrão são sincronizados, o que, na prática, permite misturar E / S no estilo C e C ++ e obter resultados esperados e sensíveis. Se você desativar a sincronização, os fluxos C ++ poderão ter seus próprios buffers independentes, o que torna uma mistura de E / S nos estilos C e C ++.

Lembre-se também de que os fluxos C ++ sincronizados são seguros para threads (a saída de diferentes threads pode se intercalar, mas você não obtém corridas de dados).

cin.tie(NULL);

Isso desata cinde cout. Os fluxos vinculados garantem que um fluxo seja liberado automaticamente antes de cada operação de E / S no outro fluxo.

Por padrão, cinestá vinculado couta garantir uma interação sensata do usuário. Por exemplo:

std::cout << "Enter name:";
std::cin >> name;

Se cine coutestiver empatado, você pode esperar que a saída seja liberada (ou seja, visível no console) antes que o programa solicite a entrada do usuário. Se você desatar os fluxos, o programa poderá bloquear a espera do usuário digitar seu nome, mas a mensagem "Enter name" ainda não está visível (porque couté armazenada em buffer por padrão, a saída é liberada / exibida no console somente sob demanda ou quando o buffer está cheio).

Então, se você desatar cina partir cout, você deve certificar-se para lavar coutmanualmente cada vez que você deseja exibir algo antes de esperar a entrada em cin.

Em conclusão, saiba o que cada um deles faz, entenda as conseqüências e decida se você realmente deseja ou precisa do possível efeito colateral da melhoria da velocidade.

Ionut
fonte
Quando você diz "você deve certificar-se de descarregar o cout manualmente toda vez que desejar exibir algo antes de esperar a entrada no cin", isso pode ser tão simples quanto anexar "... << std :: flush" ou "... < <std :: endl "até o final de cada linha que começa com" std :: cout << ... ", certo?
Alan
4
Sim, é tão simples assim, mas tenha cuidado com a parte "final de cada linha". couté armazenado em buffer por um motivo, se você o descarregar com muita frequência, quando realmente não precisa, poderá ocorrer um impacto no desempenho.
Ionut
@Iutut existe algo equivalente à funcionalidade tie () em C para scanf, printf?
iajnr
1
@iajnr Não, não diretamente. Em C, você pode liberar manualmente antes scanf(), desabilitar o buffer completamente ou alternar para buffer de linha (que deve liberar após a nova linha ou quando a entrada for lida stdin- consulte linux.die.net/man/3/setlinebuf ).
Ionut
1
No leetcode, melhora significativamente o tempo de execução, talvez esses sites competitivos façam algo especial para testes de entrada.
P0W 25/12/19
17

Isso é para sincronizar IOs do mundo C e C ++. Se você sincronizar, terá uma garantia de que os pedidos de todas as E / S são exatamente o que você espera. Em geral, o problema é o armazenamento em buffer de E / S que causa o problema. A sincronização permite que os dois mundos compartilhem os mesmos buffers. Por exemplo cout << "Hello"; printf("World"); cout << "Ciao";; sem sincronização você nunca vai saber se você terá HelloCiaoWorldou HelloWorldCiaoou WorldHelloCiao...

tiepermite que você garanta que os canais de pedidos de veiculação no mundo C ++ estejam ligados entre si, o que significa, por exemplo, que todas as saídas foram liberadas antes que as entradas ocorram (pense em cout << "What's your name ?"; cin >> name;).

Você sempre pode misturar IOs C ou C ++, mas se desejar um comportamento razoável, deverá sincronizar os dois mundos. Cuidado: em geral, não é recomendável combiná-los, se você programar em C, usar o C stdio e se programar em C ++, usar fluxos. Mas você pode querer misturar as bibliotecas C existentes no código C ++ e, nesse caso, é necessário sincronizar as duas.

Jean-Baptiste Yunès
fonte
3
Mesmo sem sincronização, chamadas diferentes para cout <<não podem mudar de ordem, portanto, CiaoHelloWorldnão é possível para o seu caso de exemplo. A sincronização é estritamente sobre diferentes métodos de buffer.
Mikko Rantalainen 7/10/19
3

O uso ios_base::sync_with_stdio(false);é suficiente para desacoplar os fluxos Ce C++. Você pode encontrar uma discussão sobre isso em IOStreams e localizações padrão do C ++ , de Langer e Kreft. Eles observam que como isso funciona é definido pela implementação.

A cin.tie(NULL)chamada parece estar solicitando uma dissociação entre as atividades em cine cout. Não sei explicar por que usar isso com a outra otimização deve causar uma falha. Como observado, o link que você forneceu é ruim, portanto não há especulação aqui.

Don Wakefield
fonte
0

É apenas coisas comuns para fazer cin entrada funcione mais rapidamente.

Para uma explicação rápida: a primeira linha desativa a sincronização de buffer entre o cin stream e as ferramentas stdio estilo C (como scanf ou gets) - para que o cin funcione mais rápido, mas você não pode usá-lo simultaneamente com as ferramentas stdio .

A segunda linha desativa cin do cout - por padrão, o buffer do cout libera cada vez que você lê algo do cin . E isso pode ser lento quando você lê repetidamente algo pequeno e depois escreve algo pequeno várias vezes. Portanto, a linha desativa essa sincronização (amarrando literalmente cin a nulo em vez de cout ).

Sravya
fonte