c++ - enclosed - Inicializando... ¿cuál es más eficiente?
brace enclosed initializer list (4)
Compila ambos, mira al ensamblador. El primero es una instrucción menos ...
; 9 : std::string f("Hello");
push OFFSET ??_C@_05COLMCDPH@Hello?$AA@
lea ecx, DWORD PTR _f$[esp+80]
call DWORD PTR __imp_??0?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QAE@PBD@Z
; 10 : std::string g = "Hello";
push OFFSET ??_C@_05COLMCDPH@Hello?$AA@
lea ecx, DWORD PTR _g$[esp+80]
mov DWORD PTR __$EHRec$[esp+88], 0
call DWORD PTR __imp_??0?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QAE@PBD@Z
... pero eso es un artefacto, porque fue el primero que vio el compilador. Cambia el código intercambiando el orden:
; 9 : std::string g1 = "Hello";
push OFFSET ??_C@_05COLMCDPH@Hello?$AA@
lea ecx, DWORD PTR _g1$[esp+136]
call DWORD PTR __imp_??0?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QAE@PBD@Z
; 10 : std::string f1("Hello");
push OFFSET ??_C@_05COLMCDPH@Hello?$AA@
lea ecx, DWORD PTR _f1$[esp+136]
mov DWORD PTR __$EHRec$[esp+144], 0
call DWORD PTR __imp_??0?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QAE@PBD@Z
... y he aquí, el segundo es una instrucción menos.
También vemos que este compilador (Microsoft VC ++ 2005, Configuración de versión) generó el mismo ensamblador para ambas versiones. Por lo tanto, no hay diferencia en este compilador, y usted puede probarlo.
Tengo la siguiente pregunta. ¿Cuál de estos es mejor que se debe seguir y por qué?
string strMyString = "SampleString";
o
string strMyString("SampleString");
Gracias por adelantado.
La única diferencia real es que la primera requiere técnicamente el uso del constructor de copia, pero el compilador puede eludirla para que la eficacia sea idéntica en ambos casos.
Sin embargo, el primero requiere que el constructor de copia sea accesible (es decir, no privado), incluso si no se usa realmente.
Las otras respuestas son todas correctas, pero recuerde que probablemente no importe. Va a ser raro, muy raro, increíblemente raro, que la eficiencia de la inicialización de cadenas afecte la velocidad de su programa incluso en una fracción de segundo.
La pregunta en sí es divertida porque ayuda a mostrar las operaciones de los constructores y las asignaciones de C ++, pero en la práctica si estás perdiendo el tiempo tratando de optimizar esto (y publicar en SO es evidencia suficiente de que eres ...) realmente estás inclinando en molinos de viento.
Es mejor evitar la distracción y gastar tu esfuerzo en otro lado.
Lo respondí aquí
Una cosa que puse en esta respuesta aquí: tampoco está usando ningún operador de asignación .
Breve explicación para la cosa específica de la cadena sin embargo. std::string
tiene un constructor tomando un argumento que acepta char const*
:
// simplified to a normal class declaration. std::string actually
// is a template instantiation.
class string {
public:
string(char const* str) {
// copy over...
}
};
Ahora ves que tiene un constructor tomando un puntero a personaje (s). Para que pueda aceptar un literal de cadena. Creo que el siguiente caso es obvio entonces:
string s("hello");
Llamará directamente al constructor e inicializará s
. Esto se llama inicialización directa .
La otra forma de inicializar una variable se llama inicialización de copia . El estándar dice que en el caso de la inicialización de copia, donde el inicializador no tiene el tipo de objeto que está inicializando, el inicializador se convierte al tipo correcto.
// uses copy initialization
string s = "hello";
Primero, indiquemos los tipos
-
s
tiene tipo std :: cadena -
"hello"
es una matriz, que en este caso se maneja como un puntero. Por lo tanto, lo consideraremos comochar const*
.
El compilador busca dos formas de hacer la conversión.
- ¿Hay un constructor de conversión en std :: string?
- ¿El inicializador tiene un tipo que tiene una función de operador de conversión que devuelve
std::string
?
std::string
temporal de una de esas formas que luego se utilizará para inicializar los objetos mediante el constructor de copias de std::string
. Y ve que std::string
tiene un constructor de conversión que acepta el inicializador. Entonces lo usa. Al final, es efectivamente lo mismo que
std::string s(std::string("hello"));
Tenga en cuenta que el formulario que se utiliza en su ejemplo que desencadenó todo eso
std::string s = "hello";
define una conversión implícita . Puede marcar al constructor tomando el char const*
como explícito para sus tipos si se pregunta acerca de las reglas de inicialización para sus cosas, y ya no le permitirá usar el constructor correspondiente como un constructor de conversión :
class string {
public:
explicit string(char const* str) {
// copy over...
}
};
¡Con eso, ahora está prohibido inicializarlo con una copy initialization
y un char const*
(y en varios otros lugares)!
Ahora, eso fue si el compilador no admite la elisión de temporarios en varios lugares. El compilador puede suponer que un constructor de copia copia en este contexto, y puede eliminar la copia adicional de la cadena temporal, y en su lugar construir la cadena std :: temporal directamente en el objeto inicializado. Sin embargo, el constructor de copia debe ser accesible en particular. Entonces, la inicialización de la copia no es válida si haces esto
class string {
public:
explicit string(char const* str) {
// copy over...
}
private: // ugg can''t call it. it''s private!
string(string const&);
};
Ahora, en realidad, solo el caso de inicialización directa es válido.