sirve que para library funcion clase c_str c++ string return-value

c++ - que - ¿Debo devolver std:: strings?



string copy c++ (12)

Devuelve el hilo, no es una pérdida tan grande en términos de rendimiento, pero seguramente facilitará tu trabajo después.

Además, siempre puedes alinear la función, pero la mayoría de los optimizadores lo arreglarán de todos modos.

Estoy intentando usar std::string lugar de char* siempre que sea posible, pero me preocupa que pueda estar degradando el rendimiento demasiado. ¿Es esta una buena forma de devolver cadenas de caracteres (sin errores para verificar la brevedad)?

std::string linux_settings_provider::get_home_folder() { return std::string(getenv("HOME")); }

Además, una pregunta relacionada: cuando acepte cadenas como parámetros, ¿debería recibirlos como const std::string& o const char* ?

Gracias.


Devuelve la cadena.

Creo que la mejor abstracción vale la pena. Hasta que pueda medir una diferencia de rendimiento significativa, yo diría que es una micro-optimización que solo existe en su imaginación.

Pasaron muchos años para obtener una buena abstracción de cuerdas en C ++. No creo que Bjarne Stroustroup, tan famoso por su dictamen conservador "solo pague por lo que usa", hubiera permitido un asesino de rendimiento evidente en el idioma. Una mayor abstracción es buena.


Devuelve la cuerda, como todo el mundo dice.

cuando acepto cadenas como parámetros, ¿debería recibirlas como const std::string& o const char* ?

Yo diría que tome cualquier parámetro de const por referencia, a menos que sea lo suficientemente liviano como para tomarlo por valor, o en aquellos casos excepcionales en los que necesite un puntero nulo para ser una entrada válida que signifique "ninguna de las anteriores". Esta política no es específica de cadenas.

Los parámetros de referencia no const son discutibles, ya que desde el código de llamada (sin un IDE bueno), no se puede ver inmediatamente si se transfieren por valor o por referencia, y la diferencia es importante. Entonces el código puede no estar claro. Para const params, eso no se aplica. Las personas que leen el código de llamada generalmente pueden asumir que no es su problema, por lo que solo ocasionalmente deberán verificar la firma.

En el caso de que vayas a tomar una copia del argumento en la función, tu política general debería ser tomar el argumento por valor. Entonces ya tiene una copia que puede usar, y si la hubiera copiado en una ubicación específica (como un miembro de datos), puede moverla (en C ++ 11) o cambiarla (en C ++ 03) para conseguirlo allí. Esto le da al compilador la mejor oportunidad para optimizar los casos en que la persona que llama pasa un objeto temporal.

Para string en particular, esto cubre el caso donde su función toma una std::string por valor, y la persona que llama especifica como una expresión de argumento una cadena literal o una char* apuntando a una cadena terminada en nulo. Si tomó una const std::string& y la copió en la función, eso daría como resultado la construcción de dos cadenas.


El costo de copiar cadenas por valor varía según la implementación de STL con la que está trabajando:

  • std :: string en MSVC utiliza la optimización de cadena corta, de modo que las cadenas cortas (<16 caracteres iirc) no requieren ninguna asignación de memoria (se almacenan dentro de std :: string), mientras que las más largas requieren una asignación de pila cada vez que se copia la cadena

  • std :: string bajo GCC usa una implementación contada de referencia: cuando se construye una std :: string desde un char *, se realiza una asignación de montón cada vez, pero cuando se pasa por valor a una función, simplemente se incrementa el recuento de referencias, evitando el asignación de memoria.

En general, es mejor olvidarse de lo anterior y devolver std :: cadenas por valor, a menos que lo haga miles de veces por segundo.

re: paso de parámetros, tenga en cuenta que hay un costo al pasar de char * -> std :: string, pero no de ir de std :: string-> char *. En general, esto significa que es mejor que acepte una referencia constante a std :: string. Sin embargo, la mejor justificación para aceptar un const std :: string & como argumento es que el destinatario no tiene que tener código adicional para la comprobación en lugar de nulo.


En su caso, la optimización del valor de retorno tendrá lugar, por lo que std :: string no se copiará.


Es de naturaleza humana preocuparse por el rendimiento, especialmente cuando el lenguaje de programación admite la optimización de bajo nivel. Lo que no deberíamos olvidar como programadores es que el rendimiento del programa es solo una de las muchas cosas que podemos optimizar y admirar. Además de la velocidad del programa, podemos encontrar belleza en nuestra propia actuación. Podemos minimizar nuestros esfuerzos al tratar de lograr el máximo rendimiento visual y la interactividad de la interfaz del usuario. ¿Crees que podría ser más motivación que preocuparse por bits y ciclos a largo plazo ... Entonces sí, devolver la cadena: s. Minimizan el tamaño de tu código y tus esfuerzos, y hacen que la cantidad de trabajo que realizas sea menos deprimente.


Estoy de acuerdo con @duffymo. No optimice hasta que haya medido, esto es doblemente cierto al hacer micro optimizaciones. Y siempre: mida antes y después de haber optimizado, para ver si realmente cambió las cosas a mejor.


Estoy de acuerdo con Duffymo. Primero debe hacer una aplicación de trabajo comprensible y luego, si es necesario, optimizar los ataques. Es en este punto que tendrá una idea de dónde están los principales cuellos de botella y podrá administrar de manera más eficiente su tiempo para hacer una aplicación más rápida.


Estoy de acuerdo con los otros carteles, que deberías usar una cuerda.

Pero sepa, que dependiendo de qué tan agresivamente su compilador optimice los temporales, probablemente tendrá un poco de sobrecarga adicional (sobre el uso de una matriz dinámica de caracteres). (Nota: la buena noticia es que en C ++ 0a, el uso sensato de las referencias de rvalue no requerirá optimizaciones del compilador para comprar eficiencia aquí, y los programadores podrán hacer algunas garantías adicionales de rendimiento sobre su código sin depender de la calidad de el compilador)

En su situación, ¿vale la pena administrar una memoria manual adicional? La mayoría de los programadores razonables estarían en desacuerdo, pero si tu aplicación termina teniendo problemas de rendimiento, el siguiente paso sería perfilar tu aplicación, por lo tanto, si introduces complejidad, solo lo haces una vez que tienes buena evidencia de que es necesario mejorarla. eficiencia general

Alguien mencionó que la optimización del valor de retorno (RVO) es irrelevante aquí. No estoy de acuerdo.

El texto estándar (C ++ 03) en este lee (12.2):

[Comience la cotización estándar]

Los temporarios del tipo de clase se crean en varios contextos: vinculando un valor r a una referencia (8.5.3), devolviendo un valor r (6.6.3), una conversión que crea un valor r (4.1, 5.2.9, 5.2.11, 5.4) , lanzando una excepción (15.1), ingresando un controlador (15.3), y en algunas inicializaciones (8.5). [Nota: la duración de los objetos de excepción se describe en 15.1. ] Incluso cuando se evita la creación del objeto temporal (12.8), todas las restricciones semánticas deben respetarse como si se hubiera creado el objeto temporal. [Ejemplo: incluso si no se llama al constructor de copia, se cumplirán todas las restricciones semánticas, como la accesibilidad (cláusula 11). ]

[Example: struct X { X(int); X(const X&); ˜X(); }; X f(X); void g() { X a(1); X b = f(X(2)); a = f(a); }

Aquí, una implementación podría usar un temporal en el cual construir X (2) antes de pasarlo a f () usando el constructor de copias de X; alternativamente, X (2) podría construirse en el espacio utilizado para contener el argumento. Además, se puede usar un temporal para mantener el resultado de f (X (2)) antes de copiarlo a b usando copyconstructor de X; alternativamente, el resultado de f () podría construirse en b. Por otro lado, la expresión a = f (a) requiere un temporal para el argumento a o el resultado de f (a) para evitar el alias no deseado de a. ]

[Fin de la cita estándar]

Esencialmente, el texto anterior dice que posiblemente puede confiar en RVO en situaciones de inicialización, pero no en situaciones de asignación. La razón es que cuando se inicializa un objeto, no hay forma de que la inicialización tenga alias al objeto mismo (por lo que nunca se hace una autoverificación en un constructor de copia), pero cuando lo hace una tarea, podría.

No hay nada acerca de su código, que prohíbe inherentemente a RVO, pero lea la documentación del compilador para asegurarse de que realmente puede confiar en él, si realmente lo necesita.



Si pasa una cadena referenciada y trabaja en esa cadena, no necesita devolver nada. ;)


Tenga cuidado cuando cruce los límites del módulo.

Entonces es mejor devolver tipos primitivos ya que los tipos C ++ no son necesariamente compatibles con binarios incluso en versiones diferentes del mismo compilador.