usar resueltos leer funciones ejercicios ejemplos declarar como caracteres cadenas cadena arreglo c++ multithreading string copy-on-write

resueltos - funciones de cadenas de caracteres en c++



¿Qué clases de cadena usar en C++? (7)

En realidad, la respuesta puede ser "Depende". Pero, si está utilizando MFC, IMHO, el uso de CString sería mejor. Además, también puede utilizar CString con contenedores STL. Pero, llevará a otra pregunta, ¿debo usar contenedores STL o contenedores MFC con CString? El uso de CString proporcionará agilidad a su aplicación, por ejemplo, en conversiones Unicode.

EDITAR: Por otra parte, si utiliza llamadas a la API WIN32, las conversiones de CString serán más fáciles.

EDITAR: CString tiene un GetBuffer () y sobre métodos que le permiten modificar el búfer directamente.

EDITAR: He utilizado CString en nuestro contenedor de SQLite, y formatear CString es más fácil.

bool RS::getString(int idx, CString& a_value) { //bla bla if(getDB()->getEncoding() == IDatabase::UTF8){ a_value.Format(_T("%s"), sqlite3_column_text(getCommand()->getStatement(), idx)); }else{ a_value.Format(_T("%s"), sqlite3_column_text16(getCommand()->getStatement(), idx)); } return true; }

tenemos una aplicación de escritorio multiproceso en C ++ (MFC). Actualmente los desarrolladores usan CString o std :: string, probablemente dependiendo de su estado de ánimo. Así que nos gustaría elegir una implementación única (probablemente algo diferente a esos dos).

CString de MFC se basa en el lenguaje de copia y escritura (COW), y algunas personas dirían que esto es inaceptable en un entorno de multiproceso (y probablemente una referencia a este artículo ). No estoy convencido de tales afirmaciones, ya que los contadores atómicos parecen ser bastante rápidos, y también esta sobrecarga se ve compensada de alguna manera por una reducción en las reasignaciones de memoria.

Aprendí que la implementación de std :: string depende del compilador: no es COW en MSVC, pero sí lo es o estaba en gcc. Por lo que entendí, el nuevo estándar de C ++ 0x solucionará esto al requerir una implementación que no sea de COW y resolver algunos otros problemas, como los requisitos de búferes contiguos. Así que en realidad std :: string no se ve bien definido en este punto ...

Un ejemplo rápido de lo que no me gusta de std :: string: no hay forma de devolver una cadena desde una función sin reasignaciones excesivas (copie el constructor si se devuelve por valor, y no tenga acceso al búfer interno para optimizarlo). por referencia "por ejemplo, std::string& Result no ayuda). Puedo hacer esto con CString ya sea devolviéndolo por valor (sin copia debido a COW) o pasando por referencia y accediendo directamente al búfer. Nuevamente, C ++ 0x al rescate con sus referencias de valor, pero no vamos a tener C ++ 0x en la función más cercana.

¿Qué clase de cadena deberíamos usar? ¿Puede COW realmente convertirse en un problema? ¿Existen otras implementaciones eficientes de cadenas utilizadas comúnmente? Gracias.

EDIT: No usamos Unicode en este momento, y es poco probable que lo necesitemos. Sin embargo, si hay algo que sea fácilmente compatible con Unicode (no a costa de UCI ...), eso sería una ventaja.


No conozco ninguna otra implementación de cadenas comunes, todas ellas tienen las mismas limitaciones de lenguaje en C ++ 03. O bien ofrecen algo específico, como el hecho de que los componentes de la ICU son excelentes para Unicode, son realmente viejos como CString, o std :: string los supera.

Sin embargo, puede utilizar la misma técnica que utiliza la STL de MSVC9 SP1, es decir, "swaptimization", que es la optimización con el nombre más hilarante de la historia.

void func(std::string& ref) { std::string retval; // ... std::swap(ref, retval); // No copying done here. }

Si generó una clase de cadena personalizada que no asignó nada en su constructor predeterminado (o verificó su implementación de STL), entonces la swaptimizing no garantizaría asignaciones redundantes. Por ejemplo, mi MSVC STL usa el SSO y no asigna ninguna memoria del montón de forma predeterminada, por lo que al realizar el swaptimizing lo anterior, no obtengo asignaciones redundantes.

También podría mejorar sustancialmente el rendimiento simplemente al no usar la costosa asignación de almacenamiento dinámico. Hay asignadores diseñados para asignaciones temporales, y puede reemplazar el asignador utilizado en su implementación de STL favorita por uno personalizado. Puedes obtener cosas como grupos de objetos desde Boost o hacer rodar un campo de memoria. Puede obtener diez veces mejor rendimiento en comparación con una nueva asignación normal.


Recomendaría usar std :: basic_string como su base de plantilla de cadena general, a menos que haya una buena razón para hacerlo de otra manera. Digo basic_string porque si está manejando caracteres de 16 bits, usaría wstring.

Si va a utilizar TCHAR, probablemente debería definir tstring como basic_string y tal vez desee implementar una clase de rasgos para usar funciones como _tcslen, etc.


Sugeriría tomar una decisión "por DLL". Si tiene DLL que dependen mucho de MFC (por ejemplo, su capa GUI), donde necesita muchas llamadas MFC con parámetros de CString , use CString . Si tiene DLL donde la única cosa de MFC que va a utilizar sería la clase CString, use std::string lugar. Por supuesto, necesitará la función de conversión entre ambas clases, pero sospecho que ya ha resuelto ese problema.


Yo digo que siempre vaya por std::string . Como se mencionó, RVO y NVRO harán que las copias sean baratas, y cuando finalmente cambies a C ++ 0x, obtendrás un buen aumento de rendimiento de la semántica de movimientos, sin hacer nada. Si desea tomar cualquier código y usarlo en un proyecto que no sea de ATL / MFC, no puede usar CString, pero std::string estará allí, por lo que tendrá un tiempo mucho más fácil. Finalmente, mencionó en un comentario que usa contenedores STL en lugar de contenedores MFC (buena jugada). ¿Por qué no mantener la coherencia y usar la cadena STL también?


Yo usaría std::string .

  • Promover el desacoplamiento de MFC
  • Mejor interacción con las bibliotecas C ++ existentes.

El problema de "devolución por valor" es en su mayor parte un problema. Los compiladores son muy buenos para realizar la Optimización del valor de retorno (RVO), lo que elimina la copia en la mayoría de los casos cuando se devuelve por valor. Si no lo hace, por lo general puede ajustar la función.

El COW ha sido rechazado por una razón: no se escala (bueno) y el esperado aumento de velocidad no se ha medido realmente (consulte el artículo de Herb Sutter). Las operaciones atómicas no son tan baratas como parecen. Con el mono-procesador mono-core fue fácil, pero ahora los multi-core son básicos y los multiprocesadores están ampliamente disponibles (para servidores). En tales arquitecturas distribuidas hay múltiples cachés, que necesitan sincronizarse, y cuanto más distribuida esté la arquitectura, más costosas serán las operaciones atómicas.

¿ CString implementa la optimización de cadenas pequeñas ? Es un truco simple que permite que una cadena no asigne memoria a cadenas pequeñas (generalmente unos pocos caracteres). Muy útil porque resulta que la mayoría de las cadenas son de hecho pequeñas, ¿cuántas cadenas en su aplicación tienen menos de 8 caracteres?

Entonces, a menos que me presente un punto de referencia real que muestre claramente una ganancia neta en el uso de CString , preferiría seguir el estándar: es estándar, y probablemente mejor optimizado.


std::string generalmente se cuenta como referencia, por lo que el paso por valor sigue siendo una operación barata (y más aún con el valor de referencia de valor en C ++ 0x). El COW se activa solo para cadenas que tienen varias referencias que apuntan a ellas, es decir:

std::string foo("foo"); std::string bar(foo); foo[0] = ''m'';

Pasará por el camino de VACA. A medida que el COW ocurre dentro del operator[] , puede forzar a una cadena a usar un búfer privado usando sus métodos del operator[]() (no constante) operator[]() o begin() .