{"id":32466,"date":"2019-10-31T21:47:13","date_gmt":"2019-10-31T18:47:13","guid":{"rendered":"https:\/\/prohoster.info\/blog\/kak-my-pereveli-10-millionov-strok-koda-c-na-standart-c-14-a-potom-i-na-c-17\/"},"modified":"2019-10-31T21:47:13","modified_gmt":"2019-10-31T18:47:13","slug":"kak-my-pereveli-10-millionov-strok-koda-c-na-standart-c-14-a-potom-i-na-c-17","status":"publish","type":"post","link":"https:\/\/prohoster.info\/pt\/blog\/administrirovanie\/kak-my-pereveli-10-millionov-strok-koda-c-na-standart-c-14-a-potom-i-na-c-17","title":{"rendered":"Como traduzimos 10 milh\u00f5es de linhas de c\u00f3digo C++ para o padr\u00e3o C++14 (e depois para C++17)","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p>H\u00e1 algum tempo atr\u00e1s (no outono de 2016), durante o desenvolvimento de mais uma vers\u00e3o da plataforma tecnol\u00f3gica 1C:Enterprise, surgiu a quest\u00e3o dentro da equipe de desenvolvimento sobre o suporte a um novo padr\u00e3o <noindex><a rel=\"nofollow\" href=\"https:\/\/ru.wikipedia.org\/wiki\/C%2B%2B14\">C++14<\/a><\/noindex> em nosso c\u00f3digo. A transi\u00e7\u00e3o para o novo padr\u00e3o, como sup\u00fanhamos, nos permitiria escrever muitas coisas de forma mais elegante, simples e confi\u00e1vel, facilitando a manuten\u00e7\u00e3o e o suporte do c\u00f3digo. E, em tradu\u00e7\u00e3o, n\u00e3o parece haver nada extraordin\u00e1rio, se n\u00e3o fossem as dimens\u00f5es da base de c\u00f3digo e as caracter\u00edsticas espec\u00edficas do nosso c\u00f3digo.<\/p>\n<p>Para quem n\u00e3o sabe, 1C:Enterprise \u00e9 um ambiente para o r\u00e1pido desenvolvimento de aplicativos de neg\u00f3cios multiplataforma e runtime para sua execu\u00e7\u00e3o em diferentes sistemas operacionais e bancos de dados. Em termos gerais, o produto inclui:<\/p>\n<ul>\n<li><noindex><a rel=\"nofollow\" href=\"http:\/\/v8.1c.ru\/overview\/Term_000000885.htm\">Um cluster de servidores de aplicativos<\/a><\/noindex>, que funciona em Windows e Linux<\/li>\n<li><noindex><a rel=\"nofollow\" href=\"http:\/\/v8.1c.ru\/overview\/Term_000000124.htm\">Cliente<\/a><\/noindex>, se comunicando com o servidor via http(s) ou atrav\u00e9s de seu pr\u00f3prio protocolo bin\u00e1rio, funcionando em Windows, Linux, macOS<\/li>\n<li><noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/company\/1c\/blog\/315414\/\">Cliente web<\/a><\/noindex>, que opera nos navegadores Chrome, Internet Explorer, Microsoft Edge, Firefox, Safari (escrito em JavaScript)<\/li>\n<li>Um ambiente de desenvolvimento (<noindex><a rel=\"nofollow\" href=\"http:\/\/v8.1c.ru\/overview\/Term_000000008.htm\">Configurador<\/a><\/noindex>), funcionando em Windows, Linux, macOS<\/li>\n<li><noindex><a rel=\"nofollow\" href=\"http:\/\/v8.1c.ru\/overview\/Term_000000813.htm\">Ferramentas de administra\u00e7\u00e3o<\/a><\/noindex> de servidores de aplicativos, que funcionam em Windows, Linux, macOS<\/li>\n<li><noindex><a rel=\"nofollow\" href=\"https:\/\/wonderland.v8.1c.ru\/blog\/mobilnyy-klient\/\">Um cliente m\u00f3vel<\/a><\/noindex>, que se conecta ao servidor via http(s), funciona em dispositivos m\u00f3veis com Android, iOS, Windows<\/li>\n<li><noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/company\/1c\/blog\/283198\/\">Uma plataforma m\u00f3vel<\/a><\/noindex> \u2014 um framework para a cria\u00e7\u00e3o de aplicativos m\u00f3veis offline com possibilidade de sincroniza\u00e7\u00e3o, que operam em Android, iOS, Windows<\/li>\n<li>Ambiente de desenvolvimento <noindex><a rel=\"nofollow\" href=\"http:\/\/v8.1c.ru\/overview\/IDE\/\">Ferramentas de Desenvolvimento 1C<\/a><\/noindex>, escrito em Java<\/li>\n<li>Servidor <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/company\/1c\/blog\/422903\/\">Sistemas de Intera\u00e7\u00e3o<\/a><\/noindex><\/li>\n<\/ul>\n<p>\nNos esfor\u00e7amos ao m\u00e1ximo para escrever um \u00fanico c\u00f3digo para diferentes sistemas operacionais \u2014 a base de c\u00f3digo do servidor \u00e9 comum em 99%, a do cliente \u2014 cerca de 95%. A plataforma tecnol\u00f3gica 1C:Enterprise \u00e9 predominantemente escrita em C++ e abaixo est\u00e3o as caracter\u00edsticas aproximadas do c\u00f3digo:<\/p>\n<ul>\n<li>10 milh\u00f5es de linhas de c\u00f3digo C++,<\/li>\n<li>14 mil arquivos,<\/li>\n<li>60 mil classes,<\/li>\n<li>meia milh\u00e3o de m\u00e9todos.<\/li>\n<\/ul>\n<p>\nE tudo isso precisava ser migrado para C++14. Sobre como fizemos isso e com o que encontramos no processo, \u00e9 o que iremos compartilhar hoje.<\/p>\n<p><img decoding=\"async\" alt=\"Como traduzimos 10 milh\u00f5es de linhas de c\u00f3digo C++ para o padr\u00e3o C++14 (e depois para C++17)\" src=\"\/wp-content\/uploads\/2019\/04\/7f9270bc37fa9fd462ac9efbb12f0764.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<h3>Isen\u00e7\u00e3o de responsabilidade<\/h3>\n<p>\nTudo o que est\u00e1 escrito abaixo sobre o desempenho lento\/r\u00e1pido e o (n\u00e3o) alto consumo de mem\u00f3ria das implementa\u00e7\u00f5es de classes padr\u00e3o em v\u00e1rias bibliotecas \u00e9 v\u00e1lido PARA N\u00d3S. \u00c9 poss\u00edvel que, para suas tarefas, as implementa\u00e7\u00f5es padr\u00e3o funcionem da melhor maneira. N\u00f3s nos baseamos nas nossas necessidades: pegamos dados t\u00edpicos de nossos clientes, executamos cen\u00e1rios comuns, observamos o desempenho, o volume de mem\u00f3ria consumido, etc., e analisamos se esses resultados nos satisfazem e aos nossos clientes ou n\u00e3o. E agimos de acordo.<\/p>\n<h3>O que t\u00ednhamos<\/h3>\n<p>\nInicialmente, escrevemos o c\u00f3digo da plataforma 1C:Enterprise 8 no Microsoft Visual Studio. O projeto come\u00e7ou no in\u00edcio dos anos 2000 e tinha apenas uma vers\u00e3o para Windows. \u00c9 claro que, desde ent\u00e3o, o c\u00f3digo evoluiu ativamente, muitos mecanismos foram reescritos completamente. Mas o c\u00f3digo era escrito segundo o padr\u00e3o de 1998, e, por exemplo, os sinais de maior e menor estavam separados por espa\u00e7os para que a compila\u00e7\u00e3o fosse bem-sucedida, assim:<\/p>\n<pre><code class=\"cpp\">vector&lt;vector &gt; IntV;<\/code><\/pre>\n<p>\nEm 2006, com o lan\u00e7amento da vers\u00e3o 8.1 da plataforma, come\u00e7amos a oferecer suporte ao Linux e migramos para uma biblioteca padr\u00e3o de terceiros <noindex><a rel=\"nofollow\" href=\"http:\/\/www.stlport.org\/\">STLPort<\/a><\/noindex>. Uma das raz\u00f5es para a migra\u00e7\u00e3o foi o trabalho com strings largas. Em nosso c\u00f3digo, usamos amplamente std::wstring, baseado no tipo wchar_t. Seu tamanho no Windows \u00e9 de 2 bytes, enquanto no Linux \u00e9 de 4 bytes por padr\u00e3o. Isso levava a incompatibilidades nos nossos protocolos bin\u00e1rios entre cliente e servidor, bem como nos diversos dados persistentes. As op\u00e7\u00f5es do gcc permitem especificar que o tamanho de wchar_t durante a compila\u00e7\u00e3o deve ser tamb\u00e9m de 2 bytes, mas ent\u00e3o n\u00e3o se pode contar com a biblioteca padr\u00e3o do compilador, j\u00e1 que ela usa glibc, que por sua vez \u00e9 compilada para wchar_t de 4 bytes. Outras raz\u00f5es inclu\u00edam uma implementa\u00e7\u00e3o de classes padr\u00e3o de melhor qualidade, suporte a tabelas hash e at\u00e9 mesmo a emula\u00e7\u00e3o da sem\u00e2ntica de movimenta\u00e7\u00e3o dentro de cont\u00eaineres, da qual usamos ativamente. E outra raz\u00e3o, como se diz, last but not least, era o desempenho das strings. T\u00ednhamos nossa pr\u00f3pria classe para strings, pois, devido \u00e0 especificidade do nosso software, as opera\u00e7\u00f5es com strings s\u00e3o amplamente utilizadas e isso \u00e9 cr\u00edtico para n\u00f3s. <\/p>\n<p>Nossa string \u00e9 baseada nas ideias de otimiza\u00e7\u00e3o de strings propostas no in\u00edcio dos anos 2000 <noindex><a rel=\"nofollow\" href=\"https:\/\/ru.wikipedia.org\/wiki\/%D0%90%D0%BB%D0%B5%D0%BA%D1%81%D0%B0%D0%BD%D0%B4%D1%80%D0%B5%D1%81%D0%BA%D1%83,_%D0%90%D0%BD%D0%B4%D1%80%D0%B5%D0%B9\">por Andrei Alexandrescu<\/a><\/noindex>. Mais tarde, quando Alexandrescu trabalhava no Facebook, a partir de sua sugest\u00e3o, uma linha de c\u00f3digo com princ\u00edpios semelhantes foi utilizada no motor do Facebook (veja a biblioteca <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/facebook\/folly\">folly<\/a><\/noindex>).<\/p>\n<p>Em nossa implementa\u00e7\u00e3o, utilizamos duas tecnologias principais de otimiza\u00e7\u00e3o:<\/p>\n<ol>\n<li>Para valores curtos, \u00e9 utilizado um buffer interno dentro do pr\u00f3prio objeto string (sem necessidade de aloca\u00e7\u00e3o adicional de mem\u00f3ria).<\/li>\n<li>Para todos os demais, \u00e9 usada a mec\u00e2nica <noindex><a rel=\"nofollow\" href=\"https:\/\/ru.wikipedia.org\/wiki\/%D0%9A%D0%BE%D0%BF%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5_%D0%BF%D1%80%D0%B8_%D0%B7%D0%B0%D0%BF%D0%B8%D1%81%D0%B8\">Copy On Write<\/a><\/noindex>. O valor da string \u00e9 armazenado em um \u00fanico local, e ao atribuir\/modificar \u00e9 utilizado um contador de refer\u00eancias.<\/li>\n<\/ol>\n<p>\nPara acelerar a compila\u00e7\u00e3o da plataforma, exclu\u00edmos a implementa\u00e7\u00e3o de stream do nosso STLPort modificado (que n\u00e3o utiliz\u00e1vamos), o que resultou em um ganho de aproximadamente 20% na compila\u00e7\u00e3o. Posteriormente, tivemos que usar de forma limitada <noindex><a rel=\"nofollow\" href=\"https:\/\/ru.wikipedia.org\/wiki\/Boost\">Boost<\/a><\/noindex>. O Boost utiliza ativamente streams, especialmente em suas APIs de servi\u00e7os (por exemplo, para log), ent\u00e3o tivemos que modificar isso, excluindo o uso de streams. Isso, por sua vez, dificultou nossa migra\u00e7\u00e3o para novas vers\u00f5es do Boost. <\/p>\n<h3>A terceira abordagem<\/h3>\n<p>\nAo migrar para o padr\u00e3o C++14, consideramos as seguintes op\u00e7\u00f5es:<\/p>\n<ol>\n<li>Subir nosso STLPort modificado para o padr\u00e3o C++14. Essa op\u00e7\u00e3o \u00e9 bastante complexa, pois o suporte ao STLPort foi descontinuado em 2010, e ter\u00edamos que portar todo o seu c\u00f3digo sozinhos.<\/li>\n<li>Migrar para outra implementa\u00e7\u00e3o do STL compat\u00edvel com C++14. \u00c9 altamente desej\u00e1vel que essa implementa\u00e7\u00e3o funcione em Windows e Linux.<\/li>\n<li>Usar a biblioteca embutida no compilador correspondente para cada sistema operacional durante a compila\u00e7\u00e3o.<\/li>\n<\/ol>\n<p>\nA primeira op\u00e7\u00e3o foi descartada imediatamente devido ao volume excessivo de trabalho.<\/p>\n<p>Pensamos por um tempo na segunda op\u00e7\u00e3o; consideramos como candidato <noindex><a rel=\"nofollow\" href=\"https:\/\/libcxx.llvm.org\/\">libc++<\/a><\/noindex>, mas na \u00e9poca n\u00e3o funcionava em Windows. Para portar o libc++ para Windows, seria necess\u00e1rio realizar muito trabalho \u2014 por exemplo, escrever tudo relacionado a threads, sincroniza\u00e7\u00e3o de threads e atomicidade, uma vez que o libc++ utilizava <noindex><a rel=\"nofollow\" href=\"https:\/\/ru.wikipedia.org\/wiki\/POSIX\">POSIX API<\/a><\/noindex>.<\/p>\n<p>E escolhemos a terceira abordagem.<\/p>\n<h3>Transi\u00e7\u00e3o<\/h3>\n<p>\nAssim, precis\u00e1vamos substituir o uso do STLPort pelas bibliotecas correspondentes dos compiladores (Visual Studio 2015 para Windows, gcc 7 para Linux, clang 8 para macOS). <\/p>\n<p>Felizmente, nosso c\u00f3digo foi escrito principalmente seguindo as diretrizes e n\u00e3o utilizou truques complicados, ent\u00e3o a migra\u00e7\u00e3o para as novas bibliotecas ocorreu de forma relativamente suave, com scripts que substitu\u00edram nos arquivos de origem os nomes de tipos, classes, namespaces e includes. A migra\u00e7\u00e3o afetou 10.000 arquivos de origem (de 14.000). wchar_t foi substitu\u00eddo por char16_t; decidimos abandonar o uso de wchar_t, pois char16_t ocupa 2 bytes em todos os sistemas operacionais e n\u00e3o compromete a compatibilidade do c\u00f3digo entre Windows e Linux.<\/p>\n<p>N\u00e3o faltaram pequenas aventuras. Por exemplo, no STLPort, o iterador poderia ser implicitamente convertido em um ponteiro para o elemento, e em algumas partes do nosso c\u00f3digo isso era utilizado. Nas novas bibliotecas, isso j\u00e1 n\u00e3o era poss\u00edvel, e essas partes precisavam ser analisadas e reescritas manualmente. <\/p>\n<p>Assim, a migra\u00e7\u00e3o do c\u00f3digo foi conclu\u00edda, o c\u00f3digo compila para todos os sistemas operacionais. \u00c9 hora dos testes. <\/p>\n<p>Os testes ap\u00f3s a migra\u00e7\u00e3o mostraram uma queda de desempenho (em alguns casos, de 20 a 30%) e um aumento no consumo de mem\u00f3ria (de 10 a 15%) em compara\u00e7\u00e3o com a antiga vers\u00e3o do c\u00f3digo. Isso estava, em particular, relacionado ao desempenho sub\u00f3timo das strings padr\u00e3o. Portanto, tivemos que usar novamente a nossa pr\u00f3pria string, que foi levemente aprimorada. <\/p>\n<p>Tamb\u00e9m foi revelada uma caracter\u00edstica interessante da implementa\u00e7\u00e3o de cont\u00eaineres nas bibliotecas embutidas: cont\u00eaineres std::map e std::set vazios (sem elementos) das bibliotecas embutidas alocam mem\u00f3ria. E em nosso c\u00f3digo, devido a caracter\u00edsticas da implementa\u00e7\u00e3o, criamos, em alguns lugares, uma boa quantidade de cont\u00eaineres vazios desse tipo. Os cont\u00eaineres padr\u00e3o alocam um pouco de mem\u00f3ria, para um \u00fanico elemento raiz, mas para n\u00f3s isso se mostrou cr\u00edtico \u2013 em v\u00e1rios cen\u00e1rios, percebemos uma queda significativa no desempenho e um aumento no consumo de mem\u00f3ria (em compara\u00e7\u00e3o com o STLPort). Portanto, substitu\u00edmos esses dois tipos de cont\u00eaineres das bibliotecas embutidas por suas implementa\u00e7\u00f5es do Boost, onde esses cont\u00eaineres n\u00e3o apresentavam essa caracter\u00edstica, e isso resolveu o problema de desacelera\u00e7\u00e3o e aumento do consumo de mem\u00f3ria.<\/p>\n<p>Como \u00e9 comum ap\u00f3s mudan\u00e7as em larga escala em grandes projetos, a primeira itera\u00e7\u00e3o dos fontes n\u00e3o funcionou sem problemas, e aqui nos foi muito \u00fatil, em particular, o suporte a iteradores de depura\u00e7\u00e3o na implementa\u00e7\u00e3o do Windows. Passo a passo, avan\u00e7amos, e na primavera de 2017 (vers\u00e3o 8.3.11 1C:Enterprise), a migra\u00e7\u00e3o foi conclu\u00edda. <\/p>\n<h3>Resultados<\/h3>\n<p>\nA transi\u00e7\u00e3o para o padr\u00e3o C++14 levou cerca de 6 meses. A maior parte do tempo, um \u00fanico desenvolvedor (mas muito qualificado) trabalhou no projeto, e na fase final, membros das equipes respons\u00e1veis por \u00e1reas espec\u00edficas \u2014 UI, cluster de servidores, ferramentas de desenvolvimento e administra\u00e7\u00e3o, etc. \u2014 foram envolvidos.<\/p>\n<p>A transi\u00e7\u00e3o simplificou bastante nosso trabalho de migra\u00e7\u00e3o para as vers\u00f5es mais recentes do padr\u00e3o. Assim, a vers\u00e3o 1C:Enterprise 8.3.14 (em desenvolvimento, lan\u00e7amento programado para o in\u00edcio do pr\u00f3ximo ano) j\u00e1 foi traduzida para o padr\u00e3o <noindex><a rel=\"nofollow\" href=\"https:\/\/ru.wikipedia.org\/wiki\/C%2B%2B17\">C++17<\/a><\/noindex>. <\/p>\n<p>Ap\u00f3s a migra\u00e7\u00e3o, os desenvolvedores tiveram mais oportunidades. Se antes t\u00ednhamos nossa pr\u00f3pria vers\u00e3o modificada da STL e um namespace std, agora temos no namespace std as classes padr\u00e3o das bibliotecas integradas do compilador, no namespace stdx \u2014 nossas strings e cont\u00eaineres otimizados para nossas necessidades, e no boost \u2014 a vers\u00e3o mais recente do boost. O desenvolvedor utiliza as classes que melhor se adequam \u00e0 sua tarefa. <\/p>\n<p>A implementa\u00e7\u00e3o 'nativa' dos construtores de movimenta\u00e7\u00e3o tamb\u00e9m auxilia no desenvolvimento (<noindex><a rel=\"nofollow\" href=\"https:\/\/en.cppreference.com\/w\/cpp\/language\/move_constructor\">move constructors<\/a><\/noindex>) para v\u00e1rias classes. Se uma classe possui um construtor de movimenta\u00e7\u00e3o e essa classe \u00e9 colocada em um cont\u00eainer, a STL otimiza a c\u00f3pia dos elementos dentro do cont\u00eainer (por exemplo, quando o cont\u00eainer \u00e9 expandido e \u00e9 necess\u00e1rio alterar a capacidade e realocar a mem\u00f3ria). <\/p>\n<h3>Uma colher de veneno<\/h3>\n<p>\nO que talvez seja a consequ\u00eancia mais desagrad\u00e1vel (mas n\u00e3o cr\u00edtica) da migra\u00e7\u00e3o \u2014 encontramos um aumento no volume <noindex><a rel=\"nofollow\" href=\"https:\/\/ru.wikipedia.org\/wiki\/%D0%9E%D0%B1%D1%8A%D0%B5%D0%BA%D1%82%D0%BD%D1%8B%D0%B9_%D0%BC%D0%BE%D0%B4%D1%83%D0%BB%D1%8C\">obj-files<\/a><\/noindex>, e o resultado completo da compila\u00e7\u00e3o com todos os arquivos intermedi\u00e1rios passou a ocupar entre 60 e 70 GB. Esse comportamento est\u00e1 relacionado \u00e0s peculiaridades das bibliotecas padr\u00e3o modernas, que se tornaram menos rigorosas em rela\u00e7\u00e3o ao volume de arquivos auxiliares gerados. Isso n\u00e3o afeta o funcionamento do aplicativo compilado, mas traz v\u00e1rios inc\u00f4modos durante o desenvolvimento, especialmente aumentam o tempo de compila\u00e7\u00e3o. Tamb\u00e9m aumentam os requisitos de espa\u00e7o livre no disco dos servidores de compila\u00e7\u00e3o e nas m\u00e1quinas dos desenvolvedores. Nossos desenvolvedores trabalham paralelamente em v\u00e1rias vers\u00f5es da plataforma, e centenas de gigabytes de arquivos intermedi\u00e1rios \u00e0s vezes criam dificuldades no trabalho. O problema \u00e9 desagrad\u00e1vel, mas n\u00e3o cr\u00edtico, e sua solu\u00e7\u00e3o foi adiada por enquanto. Como uma das poss\u00edveis solu\u00e7\u00f5es, estamos considerando a t\u00e9cnica <noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Single_Compilation_Unit\">unity build<\/a><\/noindex> (isso \u00e9 usado pela Google no desenvolvimento do navegador Chrome).<br \/>\n<br \/>Fonte: <a content=\"nofollow\" rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/1c\/blog\/429678\/\">habr.com<\/a><\/p>","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"excerpt":{"rendered":"<p>\u041d\u0435\u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u0432\u0440\u0435\u043c\u044f \u043d\u0430\u0437\u0430\u0434 (\u043e\u0441\u0435\u043d\u044c\u044e 2016), \u043f\u0440\u0438 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0435 \u043e\u0447\u0435\u0440\u0435\u0434\u043d\u043e\u0439 \u0432\u0435\u0440\u0441\u0438\u0438 \u0442\u0435\u0445\u043d\u043e\u043b\u043e\u0433\u0438\u0447\u0435\u0441\u043a\u043e\u0439 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u044b 1\u0421:\u041f\u0440\u0435\u0434\u043f\u0440\u0438\u044f\u0442\u0438\u0435 \u0432\u043d\u0443\u0442\u0440\u0438 \u043a\u043e\u043c\u0430\u043d\u0434\u044b \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0432\u0441\u0442\u0430\u043b \u0432\u043e\u043f\u0440\u043e\u0441 \u043e \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0435 \u043d\u043e\u0432\u043e\u0433\u043e \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u0430 C++14 \u0432 \u043d\u0430\u0448\u0435\u043c \u043a\u043e\u0434\u0435. \u041f\u0435\u0440\u0435\u0445\u043e\u0434 \u043d\u0430 \u043d\u043e\u0432\u044b\u0439 \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442, \u043a\u0430\u043a \u043c\u044b \u043f\u0440\u0435\u0434\u043f\u043e\u043b\u0430\u0433\u0430\u043b\u0438, \u043f\u043e\u0437\u0432\u043e\u043b\u0438\u043b \u0431\u044b \u043d\u0430\u043c \u043f\u0438\u0441\u0430\u0442\u044c \u043c\u043d\u043e\u0433\u0438\u0435 \u0432\u0435\u0449\u0438 \u044d\u043b\u0435\u0433\u0430\u043d\u0442\u043d\u0435\u0439, \u043f\u0440\u043e\u0449\u0435 \u0438 \u043d\u0430\u0434\u0435\u0436\u043d\u0435\u0439, \u0443\u043f\u0440\u043e\u0449\u0430\u043b \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0443 \u0438 \u0441\u043e\u043f\u0440\u043e\u0432\u043e\u0436\u0434\u0435\u043d\u0438\u0435 \u043a\u043e\u0434\u0430. \u0418 \u0432 \u043f\u0435\u0440\u0435\u0432\u043e\u0434\u0435 \u0432\u0440\u043e\u0434\u0435 \u0431\u044b \u043d\u0435\u0442 \u043d\u0438\u0447\u0435\u0433\u043e \u044d\u043a\u0441\u0442\u0440\u0430\u043e\u0440\u0434\u0438\u043d\u0430\u0440\u043d\u043e\u0433\u043e, [&hellip;]<\/p>\n","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"author":1,"featured_media":24270,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[688],"tags":[],"class_list":["post-32466","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-administrirovanie"],"aioseo_notices":[],"aioseo_head":"\n\t\t<!-- All in One SEO 5.0.3 - aioseo.com -->\n\t<meta name=\"description\" content=\"\u041d\u0435\u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u0432\u0440\u0435\u043c\u044f \u043d\u0430\u0437\u0430\u0434 (\u043e\u0441\u0435\u043d\u044c\u044e 2016), \u043f\u0440\u0438 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0435 \u043e\u0447\u0435\u0440\u0435\u0434\u043d\u043e\u0439 \u0432\u0435\u0440\u0441\u0438\u0438 \u0442\u0435\u0445\u043d\u043e\u043b\u043e\u0433\u0438\u0447\u0435\u0441\u043a\u043e\u0439 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u044b 1\u0421:\u041f\u0440\u0435\u0434\u043f\u0440\u0438\u044f\u0442\u0438\u0435 \u0432\u043d\u0443\u0442\u0440\u0438 \u043a\u043e\u043c\u0430\u043d\u0434\u044b \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0432\u0441\u0442\u0430\u043b \u0432\u043e\u043f\u0440\u043e\u0441 \u043e \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0435 \u043d\u043e\u0432\u043e\u0433\u043e \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u0430\" \/>\n\t<meta name=\"robots\" content=\"max-image-preview:large\" \/>\n\t<meta name=\"author\" content=\"Yuri Gagarin\"\/>\n\t<link rel=\"canonical\" href=\"https:\/\/prohoster.info\/pt\/blog\/administrirovanie\/kak-my-pereveli-10-millionov-strok-koda-c-na-standart-c-14-a-potom-i-na-c-17\" \/>\n\t\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.3\" \/>\n\t\t<meta property=\"og:locale\" content=\"pt_PT\" \/>\n\t\t<meta property=\"og:site_name\" content=\"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b\" \/>\n\t\t<meta property=\"og:type\" content=\"article\" \/>\n\t\t<meta property=\"og:title\" content=\"\ud83e\udd47\u041a\u0430\u043a \u043c\u044b \u043f\u0435\u0440\u0435\u0432\u0435\u043b\u0438 10 \u043c\u0438\u043b\u043b\u0438\u043e\u043d\u043e\u0432 \u0441\u0442\u0440\u043e\u043a \u043a\u043e\u0434\u0430 C++ \u043d\u0430 \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442 C++14 (\u0430 \u043f\u043e\u0442\u043e\u043c \u0438 \u043d\u0430 C++17) | ProHoster\" \/>\n\t\t<meta property=\"og:description\" content=\"\u041d\u0435\u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u0432\u0440\u0435\u043c\u044f \u043d\u0430\u0437\u0430\u0434 (\u043e\u0441\u0435\u043d\u044c\u044e 2016), \u043f\u0440\u0438 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0435 \u043e\u0447\u0435\u0440\u0435\u0434\u043d\u043e\u0439 \u0432\u0435\u0440\u0441\u0438\u0438 \u0442\u0435\u0445\u043d\u043e\u043b\u043e\u0433\u0438\u0447\u0435\u0441\u043a\u043e\u0439 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u044b 1\u0421:\u041f\u0440\u0435\u0434\u043f\u0440\u0438\u044f\u0442\u0438\u0435 \u0432\u043d\u0443\u0442\u0440\u0438 \u043a\u043e\u043c\u0430\u043d\u0434\u044b \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0432\u0441\u0442\u0430\u043b \u0432\u043e\u043f\u0440\u043e\u0441 \u043e \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0435 \u043d\u043e\u0432\u043e\u0433\u043e \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u0430\" \/>\n\t\t<meta property=\"og:url\" content=\"https:\/\/prohoster.info\/pt\/blog\/administrirovanie\/kak-my-pereveli-10-millionov-strok-koda-c-na-standart-c-14-a-potom-i-na-c-17\" \/>\n\t\t<meta property=\"og:image\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:secure_url\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:width\" content=\"350\" \/>\n\t\t<meta property=\"og:image:height\" content=\"350\" \/>\n\t\t<meta property=\"article:published_time\" content=\"2019-10-31T18:47:13+00:00\" \/>\n\t\t<meta property=\"article:modified_time\" content=\"2019-10-31T18:47:13+00:00\" \/>\n\t\t<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<meta property=\"article:author\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<!-- All in One SEO -->\n\n","aioseo_head_json":{"title":"\ud83e\udd47Como traduzimos 10 milh\u00f5es de linhas de c\u00f3digo C++ para o padr\u00e3o C++14 (e depois para C++17) | ProHoster","description":"H\u00e1 algum tempo atr\u00e1s (no outono de 2016), durante o desenvolvimento de mais uma vers\u00e3o da plataforma tecnol\u00f3gica 1C:Enterprise, surgiu a quest\u00e3o dentro da equipe de desenvolvimento sobre o suporte a um novo padr\u00e3o","canonical_url":"https:\/\/prohoster.info\/pt\/blog\/administrirovanie\/kak-my-pereveli-10-millionov-strok-koda-c-na-standart-c-14-a-potom-i-na-c-17","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"pt_PT","og:site_name":"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b","og:type":"article","og:title":"\ud83e\udd47\u041a\u0430\u043a \u043c\u044b \u043f\u0435\u0440\u0435\u0432\u0435\u043b\u0438 10 \u043c\u0438\u043b\u043b\u0438\u043e\u043d\u043e\u0432 \u0441\u0442\u0440\u043e\u043a \u043a\u043e\u0434\u0430 C++ \u043d\u0430 \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442 C++14 (\u0430 \u043f\u043e\u0442\u043e\u043c \u0438 \u043d\u0430 C++17) | ProHoster","og:description":"\u041d\u0435\u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u0432\u0440\u0435\u043c\u044f \u043d\u0430\u0437\u0430\u0434 (\u043e\u0441\u0435\u043d\u044c\u044e 2016), \u043f\u0440\u0438 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0435 \u043e\u0447\u0435\u0440\u0435\u0434\u043d\u043e\u0439 \u0432\u0435\u0440\u0441\u0438\u0438 \u0442\u0435\u0445\u043d\u043e\u043b\u043e\u0433\u0438\u0447\u0435\u0441\u043a\u043e\u0439 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u044b 1\u0421:\u041f\u0440\u0435\u0434\u043f\u0440\u0438\u044f\u0442\u0438\u0435 \u0432\u043d\u0443\u0442\u0440\u0438 \u043a\u043e\u043c\u0430\u043d\u0434\u044b \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0432\u0441\u0442\u0430\u043b \u0432\u043e\u043f\u0440\u043e\u0441 \u043e \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0435 \u043d\u043e\u0432\u043e\u0433\u043e \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u0430","og:url":"https:\/\/prohoster.info\/pt\/blog\/administrirovanie\/kak-my-pereveli-10-millionov-strok-koda-c-na-standart-c-14-a-potom-i-na-c-17","og:image":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:secure_url":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:width":350,"og:image:height":350,"article:published_time":"2019-10-31T18:47:13+00:00","article:modified_time":"2019-10-31T18:47:13+00:00","article:publisher":"https:\/\/www.facebook.com\/prohoster","article:author":"https:\/\/www.facebook.com\/prohoster"},"aioseo_meta_data":{"post_id":"32466","title":null,"description":null,"keywords":null,"keyphrases":null,"primary_term":null,"canonical_url":null,"og_title":null,"og_description":null,"og_object_type":"default","og_image_type":"default","og_image_url":null,"og_image_width":null,"og_image_height":null,"og_image_custom_url":null,"og_image_custom_fields":null,"og_video":null,"og_custom_url":null,"og_article_section":null,"og_article_tags":null,"twitter_use_og":false,"twitter_card":"default","twitter_image_type":"default","twitter_image_url":null,"twitter_image_custom_url":null,"twitter_image_custom_fields":null,"twitter_title":null,"twitter_description":null,"schema":{"blockGraphs":[],"customGraphs":[],"default":{"data":{"Article":[],"Course":[],"Dataset":[],"FAQPage":[],"Movie":[],"Person":[],"Product":[],"ProductReview":[],"Car":[],"Recipe":[],"Service":[],"SoftwareApplication":[],"WebPage":[]},"graphName":"","isEnabled":true},"graphs":[]},"schema_type":null,"schema_type_options":null,"pillar_content":false,"robots_default":true,"robots_noindex":false,"robots_noarchive":false,"robots_nosnippet":false,"robots_nofollow":false,"robots_noimageindex":false,"robots_noodp":false,"robots_notranslate":false,"robots_max_snippet":null,"robots_max_videopreview":null,"robots_max_imagepreview":"large","priority":null,"frequency":null,"local_seo":null,"seo_analyzer_scan_date":"2026-01-21 11:00:20","breadcrumb_settings":null,"limit_modified_date":false,"reviewed_by":null,"ai":null,"created":"2021-03-01 02:58:23","updated":"2026-01-21 11:00:20","focus_keyword":null,"additional_keywords":null,"truseo_locale":null},"gt_translate_keys":[{"key":"link","format":"url"}],"_links":{"self":[{"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/posts\/32466","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/comments?post=32466"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/posts\/32466\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/media\/24270"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/media?parent=32466"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/categories?post=32466"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/tags?post=32466"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}