2011-11-09 12 views
20

Estoy aprendiendo C++ desde el principio y no entiendo todo el tema de cadenas.C++ cadena de declaración

¿Cuál es la diferencia entre los siguientes tres códigos?

  1. std::string s = std::string("foo");
  2. std::string s = new std::string("foo");
  3. std::string s = "foo";
+0

Tenga en cuenta que generalmente desea utilizar la opción 4: 'std :: string s (" foo ");' –

+0

@JerryCoffin: ¿cómo es eso diferente de la opción 3? –

+2

@MikeSeymour: inicializa directamente la inicialización en lugar de la inicialización de la copia. Al menos conceptualmente, # 3 crea una cadena temporal inicializada a partir de la constante suministrada, luego utiliza el constructor de copia para crear 's' a partir de ese valor (aunque, ciertamente, el compilador normalmente lo omitirá y hará el equivalente a la inicialización directa). –

Respuesta

32
std::string s = std::string("foo"); 

Esto crea un objeto temporal std::string que contiene "foo", entonces lo asigna a s. (Tenga en cuenta que los compiladores pueden eludir el temporal. El elison temporal en este caso se permite explícitamente por norma el C++.)

std::string s = new std::string("foo"); 

Este es un error de compilación. La expresión new std::string("foo")crea un std::string en la tienda gratuita y devuelve un puntero a std::string. A continuación, intenta asignar el puntero devuelto del tipo std::string* al s del tipo std::string. El diseño de la clase std::string impide que eso suceda, por lo que la compilación falla.

C++ no es Java. Esta no es la forma en que normalmente se crean los objetos, porque si olvida delete el objeto devuelto std::string se perderá la memoria. Uno de los principales beneficios del uso de std::string es que administra automáticamente el buffer de cadena subyacente, por lo que new -destruye ese propósito.

std::string s = "foo"; 

Esto es esencialmente lo mismo que # 1. Inicializa técnicamente una nueva cadena temporal que contendrá "foo" y la asignará al s. Una vez más, los compiladores normalmente eludirán los compiladores temporales (y de hecho casi todos los compiladores no estúpidos hoy en día lo hacen, de hecho, eliminar el temporal), por lo que en la práctica simplemente construye un nuevo objeto llamado s en su lugar.

Específicamente invoca un constructor de conversión en std::string que acepta un argumento const char*. En el código anterior, se requiere que el constructor de conversión sea no explicit; de lo contrario, se trata de un error del compilador. El constructor de conversión es, de hecho, no explicit para std::string s, por lo que lo anterior se compila.

Así es como std::string s suelen ser inicializados. Cuando s sale del alcance, el objeto s se destruirá junto con el almacenamiento intermedio de cadenas subyacente. Tenga en cuenta que lo siguiente tiene el mismo efecto (y es otra forma típica en que se inicializan std::string s), en el sentido de que también produce un objeto llamado s que contiene "foo".

std::string s("foo"); 

Sin embargo, there's a subtle difference between std::string s = "foo"; and std::string s("foo");, una de ellas es que el constructor de conversión puede ser explicit o no explicit en el caso anterior.

+2

+1 por ser la respuesta que menciona que los compiladores no crean necesariamente un temporal en el # 1. –

+1

Tenga en cuenta que los números 1 y 3 son equivalentes en lo que respecta al idioma. – avakar

+0

Entonces 'std :: string (" foo ")' crea "foo" en la pila y 'new std :: string (" foo ")' crea foo en el montón? –

2
  1. Crea un objeto temporal cuerda y copia el valor de s
  2. no compila, new std::string("foo") devuelve un puntero a una cierta memoria recién asignada. Para que esto funcione, debe declarar s como un puntero a una cadena std::string* s.
  3. Construye una cadena a partir de una C-string.

Debe utilizar la tercera opción en la mayoría, si no en todos, los casos.

2

1 creará una variable temporal (lado derecho), a continuación, llamar al operador de asignación para asignar el valor de s

2 creará una instancia de std::string en el montón y devolver un puntero a ella, y la voluntad fracasar en la tarea porque no se puede asignar un puntero a un tipo no-puntero

3 construirá un std :: string e inicializar desde un const char*

+0

"no se puede asignar un puntero a un tipo que no sea puntero": en su opinión, 'bool s; s = new std :: string ("Hello, world."); 'es un error en tiempo de compilación? Por cierto, ese signo igual no es una asignación (por ejemplo, podría ser legal escribir 'Foo x = 12;' incluso cuando 'Foo :: operator = (int)' sea privado). – 6502

+0

@ 6502: Su redacción es incorrecta, pero de cualquier manera no se puede asignar desde un 'std :: string' –

+0

@MooingDuck: Esta respuesta es simplemente incorrecta en algunos puntos: A) esas no son asignaciones, son inicializaciones (en C++ es una cosa diferente, con diferentes reglas y semántica, el operador de asignación del que se habla en 1 se llama * NO *), B) La frase "No se puede asignar un puntero a un tipo que no sea puntero" es simplemente falsa. .. puede asignar (y también inicializar) un booleano desde un puntero. El punto 2 tiene una redacción muy mala para IMO, ya que parece indicar que el código se compilará y uno obtendrá un error de tiempo de ejecución ... pero al menos hay algunas dudas de que esto no es lo que Fred quiso decir. – 6502

0

en el número 1, que está creando un temporal string usando el constructor y luego asignándolo a s. El número 2 ni siquiera compila. En el número 3, está creando una nueva cadena y luego le asigna un valor.

3
std::string s = std::string("foo"); 

Esto se llama copia de inicialización. Es funcionalmente lo mismo que la inicialización directa

std::string s("foo"); 

pero el primero requiere que el constructor de copia está disponible y compiladores puede crear un objeto temporal, pero la mayoría va a eludir el temporal y directamente s construir para contener "foo".


std::string s = new std::string("foo"); 

Esto no compilará porque new devuelve un puntero. Para que funcione, necesitaría que el tipo de s sea std::string *. A continuación, la línea asigna dinámicamente un objeto std::string y almacena el puntero en s. Necesitará delete una vez que haya terminado de usarlo.


std::string s = "foo"; 

Esto es casi el mismo que el primero. Es una inicialización de copia pero tiene una restricción adicional. Requiere que la clase std::string contenga un constructor no explicit que toma un const char *. Esto permite al compilador construir implícitamente un objeto temporal std::string. Después de eso, la semántica es idéntica a la del caso 1.

Cuestiones relacionadas