{"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\/es\/blog\/administrirovanie\/kak-my-pereveli-10-millionov-strok-koda-c-na-standart-c-14-a-potom-i-na-c-17","title":{"rendered":"C\u00f3mo traducimos 10 millones de l\u00edneas de c\u00f3digo C++ al est\u00e1ndar C++14 (y luego a C++17)","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p>Hace un tiempo (en oto\u00f1o de 2016), durante el desarrollo de una nueva versi\u00f3n de la plataforma tecnol\u00f3gica 1C:Enterprise, surgi\u00f3 dentro del equipo de desarrollo la cuesti\u00f3n del soporte para el nuevo est\u00e1ndar <noindex><a rel=\"nofollow\" href=\"https:\/\/ru.wikipedia.org\/wiki\/C%2B%2B14\">C++14<\/a><\/noindex> en nuestro c\u00f3digo. La transici\u00f3n al nuevo est\u00e1ndar, como supon\u00edamos, nos permitir\u00eda escribir muchas cosas de manera m\u00e1s elegante, sencilla y confiable, facilitando el soporte y mantenimiento del c\u00f3digo. Y en la traducci\u00f3n no parece haber nada extraordinario, si no fuera por la magnitud de la base de c\u00f3digo y las caracter\u00edsticas espec\u00edficas de nuestro c\u00f3digo.<\/p>\n<p>Para aquellos que no lo sepan, 1C:Enterprise es un entorno para el desarrollo r\u00e1pido de aplicaciones empresariales multiplataforma y un runtime para su ejecuci\u00f3n en diferentes sistemas operativos y bases de datos. En t\u00e9rminos generales, el producto incluye:<\/p>\n<ul>\n<li><noindex><a rel=\"nofollow\" href=\"http:\/\/v8.1c.ru\/overview\/Term_000000885.htm\">Un cl\u00faster de servidores de aplicaciones<\/a><\/noindex>, que funciona en Windows y Linux<\/li>\n<li><noindex><a rel=\"nofollow\" href=\"http:\/\/v8.1c.ru\/overview\/Term_000000124.htm\">Cliente<\/a><\/noindex>, que se comunica con el servidor a trav\u00e9s de http(s) o mediante su propio protocolo binario, funcionando en Windows, Linux, macOS<\/li>\n<li><noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/company\/1c\/blog\/315414\/\">Cliente web<\/a><\/noindex>, que opera en navegadores como Chrome, Internet Explorer, Microsoft Edge, Firefox, Safari (escrito en JavaScript)<\/li>\n<li>Un entorno de desarrollo (<noindex><a rel=\"nofollow\" href=\"http:\/\/v8.1c.ru\/overview\/Term_000000008.htm\">Configurador<\/a><\/noindex>), que opera en Windows, Linux, macOS<\/li>\n<li><noindex><a rel=\"nofollow\" href=\"http:\/\/v8.1c.ru\/overview\/Term_000000813.htm\">Herramientas de administraci\u00f3n<\/a><\/noindex> de servidores de aplicaciones, que funcionan en Windows, Linux, macOS<\/li>\n<li><noindex><a rel=\"nofollow\" href=\"https:\/\/wonderland.v8.1c.ru\/blog\/mobilnyy-klient\/\">Un cliente m\u00f3vil<\/a><\/noindex>, que se conecta al servidor a trav\u00e9s de http(s), operativo en dispositivos m\u00f3viles que funcionan con Android, iOS, Windows<\/li>\n<li><noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/company\/1c\/blog\/283198\/\">Una plataforma m\u00f3vil<\/a><\/noindex> \u2014 un marco para crear aplicaciones m\u00f3viles offline con capacidad de sincronizaci\u00f3n, que funcionan en Android, iOS, Windows<\/li>\n<li>Entorno de desarrollo <noindex><a rel=\"nofollow\" href=\"http:\/\/v8.1c.ru\/overview\/IDE\/\">1C:Enterprise Development Tools<\/a><\/noindex>, escrita en Java<\/li>\n<li>Servidor <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/company\/1c\/blog\/422903\/\">Sistemas de Interacci\u00f3n<\/a><\/noindex><\/li>\n<\/ul>\n<p>\nNos esforzamos por escribir un solo c\u00f3digo para diferentes sistemas operativos: la base de c\u00f3digo del servidor es com\u00fan en un 99%, la del cliente \u2014 aproximadamente un 95%. La plataforma tecnol\u00f3gica 1C:Enterprise est\u00e1 predominantemente escrita en C++ y a continuaci\u00f3n se presentan caracter\u00edsticas aproximadas del c\u00f3digo:<\/p>\n<ul>\n<li>10 millones de l\u00edneas de c\u00f3digo C++,<\/li>\n<li>14 mil archivos,<\/li>\n<li>60 mil clases,<\/li>\n<li>medio mill\u00f3n de m\u00e9todos.<\/li>\n<\/ul>\n<p>\nY todo este conjunto deb\u00eda ser migrado a C++14. Sobre c\u00f3mo lo hicimos y con qu\u00e9 nos encontramos en el proceso, hoy les contaremos.<\/p>\n<p><img decoding=\"async\" alt=\"C\u00f3mo traducimos 10 millones de l\u00edneas de c\u00f3digo C++ al est\u00e1ndar C++14 (y luego a 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>Descargo de responsabilidad<\/h3>\n<p>\nTodo lo que se ha escrito a continuaci\u00f3n sobre el funcionamiento lento\/r\u00e1pido, el bajo consumo de memoria de las implementaciones de las clases est\u00e1ndar en diversas bibliotecas significa una cosa: esto es v\u00e1lido PARA NOSOTROS. Es posible que las implementaciones est\u00e1ndar se adapten perfectamente a sus necesidades. Nosotros, en cambio, partimos de nuestras propias tareas: tomamos datos t\u00edpicos de nuestros clientes, los sometimos a escenarios t\u00edpicos, observamos el rendimiento, el volumen de memoria consumida, etc. y analizamos si estos resultados son satisfactorios para nosotros y nuestros clientes o no. Y actuamos en consecuencia.<\/p>\n<h3>Lo que ten\u00edamos<\/h3>\n<p>\nInicialmente, escrib\u00edamos el c\u00f3digo de la plataforma 1C:Enterprise 8 en Microsoft Visual Studio. El proyecto comenz\u00f3 a principios de los a\u00f1os 2000 y solo ten\u00edamos una versi\u00f3n para Windows. Por supuesto, desde entonces el c\u00f3digo ha evolucionado significativamente y muchos mecanismos han sido reescritos por completo. Sin embargo, el c\u00f3digo se escribi\u00f3 seg\u00fan el est\u00e1ndar de 1998, y, por ejemplo, los signos de mayor estaban separados por espacios para que la compilaci\u00f3n fuera exitosa, as\u00ed:<\/p>\n<pre><code class=\"cpp\">vector&lt;vector &gt; IntV;<\/code><\/pre>\n<p>\nEn 2006, con el lanzamiento de la versi\u00f3n 8.1 de la plataforma, comenzamos a soportar Linux y transicionamos a una biblioteca est\u00e1ndar de terceros <noindex><a rel=\"nofollow\" href=\"http:\/\/www.stlport.org\/\">STLPort<\/a><\/noindex>. Una de las razones para la transici\u00f3n fue trabajar con cadenas anchas. En nuestro c\u00f3digo utilizamos universalmente std::wstring, basado en el tipo wchar_t. Su tama\u00f1o en Windows es de 2 bytes, mientras que en Linux, por defecto, es de 4 bytes. Esto llev\u00f3 a incompatibilidades en nuestros protocolos binarios entre cliente y servidor, as\u00ed como con varios datos persistentes. Se pueden especificar opciones de gcc para que el tama\u00f1o de wchar_t al compilar sea tambi\u00e9n de 2 bytes, pero entonces no se puede pensar en usar la biblioteca est\u00e1ndar del compilador, ya que utiliza glibc, que a su vez est\u00e1 compilada para wchar_t de 4 bytes. Otras razones inclu\u00edan una implementaci\u00f3n de las clases est\u00e1ndar de mayor calidad, soporte para tablas hash e incluso emulaci\u00f3n de sem\u00e1ntica de movimiento dentro de los contenedores, que utiliz\u00e1bamos ampliamente. Y, como se dice, la \u00faltima pero no menos importante, fue el rendimiento de las cadenas. Ten\u00edamos nuestra propia clase para cadenas, ya que debido a la especificidad de nuestro software, las operaciones con cadenas se utilizan de manera muy amplia y esto es cr\u00edtico para nosotros. <\/p>\n<p>Nuestra cadena se basa en ideas de optimizaci\u00f3n de cadenas expresadas a principios de la d\u00e9cada de 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>. M\u00e1s tarde, cuando Alexandrescu trabajaba en Facebook, se implement\u00f3 en el motor de Facebook una cadena que funcionaba bajo principios similares (ver la biblioteca <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/facebook\/folly\">folly<\/a><\/noindex>).<\/p>\n<p>En nuestra cadena se utilizaron dos tecnolog\u00edas principales de optimizaci\u00f3n:<\/p>\n<ol>\n<li>Para valores cortos, se utiliza un b\u00fafer interno en el propio objeto de la cadena (que no requiere asignaci\u00f3n de memoria adicional).<\/li>\n<li>Para todos los dem\u00e1s se utiliza la mec\u00e1nica <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>. El valor de la cadena se almacena en un solo lugar; al asignarse\/modificarse, se usa un contador de referencias.<\/li>\n<\/ol>\n<p>\nPara acelerar la compilaci\u00f3n de la plataforma, excluimos de nuestra variante de STLPort la implementaci\u00f3n de stream (que no utilizamos), lo que nos dio una aceleraci\u00f3n de compilaci\u00f3n de aproximadamente el 20%. Posteriormente, tuvimos que utilizar. <noindex><a rel=\"nofollow\" href=\"https:\/\/ru.wikipedia.org\/wiki\/Boost\">Boost<\/a><\/noindex>. Boost utiliza intensivamente stream, en particular, en sus API de servicio (por ejemplo, para el registro), por lo que tuvimos que modificarlo, excluyendo su uso de stream. Esto, a su vez, complicaba nuestra transici\u00f3n a nuevas versiones de Boost. <\/p>\n<h3>El tercer camino<\/h3>\n<p>\nAl migrar al est\u00e1ndar C++14, consideramos las siguientes opciones:<\/p>\n<ol>\n<li>Elevar nuestra versi\u00f3n modificada de STLPort al est\u00e1ndar C++14. Esta opci\u00f3n es muy dif\u00edcil, ya que el soporte para STLPort se detuvo en 2010, y tendr\u00edamos que elevar todo su c\u00f3digo nosotros mismos.<\/li>\n<li>Migrar a otra implementaci\u00f3n de STL compatible con C++14. Es extremadamente deseable que esta implementaci\u00f3n est\u00e9 disponible para Windows y Linux.<\/li>\n<li>Utilizar la biblioteca integrada en el compilador correspondiente para la compilaci\u00f3n en cada SO.<\/li>\n<\/ol>\n<p>\nLa primera opci\u00f3n fue descartada de inmediato por el alto volumen de trabajo que implicaba.<\/p>\n<p>Pensamos un tiempo sobre la segunda opci\u00f3n; est\u00e1bamos considerando <noindex><a rel=\"nofollow\" href=\"https:\/\/libcxx.llvm.org\/\">libc++<\/a><\/noindex>, pero en ese momento no funcionaba en Windows. Para portar libc++ a Windows, ser\u00eda necesario hacer mucho trabajo, como escribir todo lo relacionado con hilos, sincronizaci\u00f3n de hilos y atomicidad, ya que en libc++ se utilizaban <noindex><a rel=\"nofollow\" href=\"https:\/\/ru.wikipedia.org\/wiki\/POSIX\">POSIX API<\/a><\/noindex>.<\/p>\n<p>Y elegimos el tercer camino.<\/p>\n<h3>Transici\u00f3n<\/h3>\n<p>\nAs\u00ed que ten\u00edamos que reemplazar el uso de STLPort por las bibliotecas de los compiladores correspondientes (Visual Studio 2015 para Windows, gcc 7 para Linux, clang 8 para macOS). <\/p>\n<p>Afortunadamente, nuestro c\u00f3digo se escribi\u00f3 principalmente seg\u00fan las pautas y no us\u00f3 trucos complicados, por lo que la migraci\u00f3n a las nuevas bibliotecas se llev\u00f3 a cabo de manera relativamente suave, con la ayuda de scripts que reemplazaban en los archivos originales los nombres de tipos, clases, espacios de nombres e inclusiones. La migraci\u00f3n afect\u00f3 a 10,000 archivos fuente (de 14,000). wchar_t fue reemplazado por char16_t; decidimos abandonar el uso de wchar_t, ya que char16_t ocupa 2 bytes en todos los sistemas operativos y no interfiere con la compatibilidad del c\u00f3digo entre Windows y Linux.<\/p>\n<p>No estuvo exenta de peque\u00f1as aventuras. Por ejemplo, en STLPort se pod\u00eda castear impl\u00edcitamente un iterador a un puntero a un elemento, y en algunos lugares de nuestro c\u00f3digo se utilizaba. En las nuevas bibliotecas esto ya no era posible, y tuvimos que analizar y reescribir manualmente esos lugares. <\/p>\n<p>As\u00ed que la migraci\u00f3n del c\u00f3digo ha terminado, el c\u00f3digo se compila para todos los sistemas operativos. Es hora de las pruebas. <\/p>\n<p>Las pruebas posteriores a la transici\u00f3n mostraron una disminuci\u00f3n en el rendimiento (en algunos casos hasta 20-30%) y un aumento en el consumo de memoria (hasta 10-15%) en comparaci\u00f3n con la versi\u00f3n anterior del c\u00f3digo. Esto estaba, en particular, relacionado con el funcionamiento sub\u00f3ptimo de las cadenas est\u00e1ndar. Por lo tanto, una vez m\u00e1s tuvimos que utilizar nuestra propia cadena, ligeramente modificada. <\/p>\n<p>Tambi\u00e9n se revel\u00f3 una caracter\u00edstica interesante de la implementaci\u00f3n de contenedores en las bibliotecas embebidas: los std::map y std::set vac\u00edos (sin elementos) de las bibliotecas embebidas asignan memoria. Y en nuestro caso, debido a las caracter\u00edsticas de la implementaci\u00f3n, se crean bastantes contenedores vac\u00edos de este tipo en algunos lugares del c\u00f3digo. Los contenedores est\u00e1ndar asignan un poco de memoria, para un elemento ra\u00edz, pero para nosotros esto result\u00f3 cr\u00edtico: en varios escenarios experimentamos una notable disminuci\u00f3n del rendimiento y un aumento en el consumo de memoria (en comparaci\u00f3n con STLPort). Por lo tanto, reemplazamos en nuestro c\u00f3digo estos dos tipos de contenedores de las bibliotecas embebidas por su implementaci\u00f3n de Boost, donde estos contenedores no ten\u00edan tal caracter\u00edstica, y esto resolvi\u00f3 el problema de la desaceleraci\u00f3n y el aumento del consumo de memoria.<\/p>\n<p>Como suele suceder despu\u00e9s de cambios a gran escala en grandes proyectos, la primera iteraci\u00f3n de los fuentes no funcion\u00f3 sin problemas, y aqu\u00ed nos fue muy \u00fatil, en particular, el soporte de iteradores de depuraci\u00f3n en la implementaci\u00f3n de Windows. Paso a paso avanzamos, y para la primavera de 2017 (versi\u00f3n 8.3.11 de 1C:Enterprise) la migraci\u00f3n fue completada. <\/p>\n<h3>Resultados<\/h3>\n<p>\nLa transici\u00f3n al est\u00e1ndar C++14 nos tom\u00f3 alrededor de 6 meses. La mayor parte del tiempo, un solo desarrollador (muy cualificado) trabaj\u00f3 en el proyecto, y en la fase final se unieron representantes de equipos responsables de \u00e1reas espec\u00edficas: UI, cl\u00faster de servidores, herramientas de desarrollo y administraci\u00f3n, etc.<\/p>\n<p>La transici\u00f3n facilit\u00f3 mucho nuestro trabajo de migraci\u00f3n a las versiones m\u00e1s recientes del est\u00e1ndar. As\u00ed, la versi\u00f3n 1C:Empresa 8.3.14 (en desarrollo, con lanzamiento programado para principios del pr\u00f3ximo a\u00f1o) ya ha sido traducida al est\u00e1ndar <noindex><a rel=\"nofollow\" href=\"https:\/\/ru.wikipedia.org\/wiki\/C%2B%2B17\">C++17<\/a><\/noindex>. <\/p>\n<p>Tras la migraci\u00f3n, los desarrolladores tienen m\u00e1s oportunidades. Si antes ten\u00edamos nuestra propia versi\u00f3n mejorada de STL y un solo namespace std, ahora en el namespace std se encuentran las clases est\u00e1ndar de las bibliotecas incorporadas del compilador, en el namespace stdx \u2013 nuestras cadenas y contenedores optimizados para nuestras tareas, y en boost \u2013 la versi\u00f3n m\u00e1s reciente de boost. Y el desarrollador utiliza las clases que se ajustan de manera \u00f3ptima a la soluci\u00f3n de sus problemas. <\/p>\n<p>Tambi\u00e9n ayuda en el desarrollo la implementaci\u00f3n 'nativa' de los constructores de movimiento (<noindex><a rel=\"nofollow\" href=\"https:\/\/en.cppreference.com\/w\/cpp\/language\/move_constructor\">move constructors<\/a><\/noindex>) para una serie de clases. Si una clase tiene un constructor de movimiento y esta clase se coloca en un contenedor, STL optimiza la copia de elementos dentro del contenedor (por ejemplo, cuando el contenedor se expande y es necesario cambiar la capacidad y realocar la memoria). <\/p>\n<h3>Una cucharada de alquitr\u00e1n<\/h3>\n<p>\nQuiz\u00e1s el resultado m\u00e1s desagradable (pero no cr\u00edtico) de la migraci\u00f3n es que nos enfrentamos a un aumento en el tama\u00f1o de <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>, y el resultado completo de la compilaci\u00f3n con todos los archivos intermedios ahora ocupa entre 60 y 70 GB. Este comportamiento est\u00e1 relacionado con las caracter\u00edsticas de las bibliotecas est\u00e1ndar modernas, que han comenzado a preocuparse menos por el volumen de archivos de servicio generados. Esto no afecta al funcionamiento de la aplicaci\u00f3n compilada, pero presenta una serie de inconvenientes en el desarrollo, especialmente aumenta el tiempo de compilaci\u00f3n. Tambi\u00e9n aumentan los requisitos de espacio libre en el disco en los servidores de compilaci\u00f3n y en las m\u00e1quinas de los desarrolladores. Nuestros desarrolladores trabajan paralelamente en varias versiones de la plataforma, y cientos de gigabytes de archivos intermedios a veces crean dificultades en el trabajo. El problema es desagradable, pero no cr\u00edtico, y por el momento hemos pospuesto su soluci\u00f3n. Como una de las opciones para resolverlo, estamos considerando la t\u00e9cnica <noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Single_Compilation_Unit\">unity build<\/a><\/noindex> (esto, en particular, lo utiliza Google al desarrollar el navegador Chrome).<br \/>\n<br \/>Fuente: <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.2 - 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\/es\/blog\/administrirovanie\/kak-my-pereveli-10-millionov-strok-koda-c-na-standart-c-14-a-potom-i-na-c-17\" \/>\n\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.2\" \/>\n\t\t<meta property=\"og:locale\" content=\"es_ES\" \/>\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\/es\/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\udd47C\u00f3mo tradujimos 10 millones de l\u00edneas de c\u00f3digo C++ al est\u00e1ndar C++14 (y luego al C++17) | ProHoster","description":"Hace un tiempo (en oto\u00f1o de 2016), durante el desarrollo de una nueva versi\u00f3n de la plataforma tecnol\u00f3gica 1C:Enterprise, surgi\u00f3 dentro del equipo de desarrollo la cuesti\u00f3n del soporte para el nuevo est\u00e1ndar","canonical_url":"https:\/\/prohoster.info\/es\/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":"es_ES","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\/es\/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\/es\/wp-json\/wp\/v2\/posts\/32466","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/comments?post=32466"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/posts\/32466\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/media\/24270"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/media?parent=32466"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/categories?post=32466"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/tags?post=32466"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}