2011-03-28 29 views
11

En el libro C++ Primer tiene un código para matrices de caracteres de estilo C, y muestra cómo sobrecargar el operador = en el Artículo 15.3 Operador =.Operador = sobrecarga en C++

String& String::operator=(const char *sobj) 
{ 
    // sobj is the null pointer, 
    if (! sobj) { 
     _size = 0; 
     delete[] _string; 
     _string = 0; 
    } 
    else { 
     _size = strlen(sobj); 
     delete[] _string; 
     _string = new char[ _size + 1 ]; 
     strcpy(_string, sobj); 
    } 
    return *this; 
} 

Ahora me gustaría saber por qué está ahí la necesidad de devolver una referencia String & cuando este código de abajo hace el mismo trabajo, sin ningún tipo de problema:

void String::operator=(const char *sobj) 
{ 
    // sobj is the null pointer, 
    if (! sobj) { 
     _size = 0; 
     delete[] _string; 
     _string = 0; 
    } 
    else { 
     _size = strlen(sobj); 
     delete[] _string; 
     _string = new char[ _size + 1 ]; 
     strcpy(_string, sobj); 
    } 

} 
  • por favor ayuda a.
+3

Tenga en cuenta que la solución que se presenta en el libro no está a salvo excepción (y sería * realmente * simple hacerlo, realmente no entiendo por qué no lo hicieron). –

Respuesta

20

Es compatible con el siguiente lenguaje:

String a, b; 
const char *c; 

// set c to something interesting 

a = b = c; 

Para que esto funcione, b = c debe devolver un objeto o referencia adecuada para asignar a a; en realidad es a = (b = c) de acuerdo con las reglas de precedencia del operador de C++.

Si devuelve el puntero this, debe escribir a = *(b = c), lo que no conlleva el significado previsto.

+1

Ahora, eso fue un trazador de líneas - ¿Por qué no escribir ese libro? Gracias. Tengo mi respuesta. – Sadique

+0

Tengo que 'esperar' durante 9 minutos para aceptar esta respuesta !!!!!! – Sadique

+1

@Acme: así es, tienes que esperar hasta que todos los demás hayan tenido la oportunidad de demostrar que estoy equivocado. –

0

El operador de regreso = es para que pueda encadenar cosas. Ver aquí sin cadenas:

x = y = 2; 

La parte y=2 de esa línea devuelve 2. Que es como x obtiene un valor. Si op = devuelto vacío, no podría encadenar = operaciones.

3

Convención. tipos incorporados lo hacen, los operadores de asignación generados automáticamente lo hacen, que le permite hacer esto:

a = b = c; 

o esto:

if (foo = come_function()) { 
    // use foo here 
} 
+0

+1 para la asignación como condicional, lo olvidé. En resumen, esta convención le ofrece todo el poder de la pistola que apunta a los programadores de C++;) –

+0

Tenga en cuenta que este último es un mal estilo y debe evitarse. –

+0

Tenga en cuenta que si este último es un estilo malo o no es una cuestión de gusto que se ha discutido en SO antes. A veces me sorprendo usando ese modismo, y todavía no estoy terriblemente avergonzado cuando lo hago. Aunque me gusta menos, entonces solía hacerlo; es un viejo hábito de los programadores de C. –

0

Por convención, que es capaz de hacer por ejemplo:

int x, y, z; 
x = y = z = 0; 

if ((x = 1) != 0) { ... } 

para mantener esta semántica para las instancias de la clase, es necesario volver *this - que permite la asignación encadenada. Si devuelve simplemente this que estaría devolviendo un puntero a la instancia, y la asignación encadenada no funcionaría - no hay operator= para String *, hay uno para String

8

@larsmans ya ha respondido a su pregunta precisa, por lo que' ll en realidad digress: Este es un código de mierda!

La cuestión aquí es de 3 veces:

  1. Usted acaba de duplicar el código del constructor de copia (un poco)
  2. strcpy podría ser mejor sustituye por strncpy, que hace algunos cota comprobar
  3. No es la excepción caja fuerte

1) y 2) son más agujas stic que nada, pero el 3) es una gran preocupación

EDIT: como señaló @Jerry Coffin, esto no protege contra la autoasignación. Es decir, si sobj y _string apuntan a la misma matriz de caracteres, tiene grandes problemas. La solución fácil al final de esta publicación también cubre esta situación.

No es seguro excepción

Vamos a echar un vistazo a una parte del código, es decir, la parte else:

_size = strlen(sobj); 
    delete[] _string; 
    _string = new char[ _size + 1 ]; 
    strcpy(_string, sobj); 

¿Qué pasa si, por alguna razón, new tiros?

  • _size tiene el valor de la nueva cadena
  • _string puntos al viejo puntero ... que ha sido liberado

Por lo tanto, no sólo el objeto se deja en un estado inutilizable (la mitad de sus datos del nuevo objeto, la mitad de la edad), pero no puede ni siquiera ser destruido (a menos que las fugas destructor ...?)

Adición de seguridad excepción, la forma más dura

_size = strlen(sobj); 
    delete[] _string; 

    try { 
    _string = new char[ _size + 1 ]; 
    } catch(...) { 
    _size = 0; _string = 0; 
    throw; 
    } 
    strcpy(_string, sobj); 

Está bien, es realmente la línea de fondo, pero nos trae la Garantía Excepción básico: hay garantía funcional, sino una garantía de que el código es técnicamente correcto (sin choque, sin fugas).

Adición de seguridad excepción, el camino más fácil: El lenguaje de copiar y de intercambio

Encuentra una descripción más completa en: What is the copy-and-swap idiom ?

void swap(String& lhs, String& rhs) { 
    using std::swap; 
    swap(lhs._size, rhs._size); 
    swap(lhs._string, rhs._string); 
} 

String& String::operator=(String other) { // pass-by-value 
    swap(*this, other); 
    return *this; 
} 

¿Cómo funciona?

  • que volver a utilizar el constructor de copia para la copia real
  • reutilizamos la función de intercambio de valores de intercambio
  • reutilizamos el destructor para la limpieza

y es incluso mejor que el versión anterior también, por ahora tenemos Strong Exception Guarantee: es transaccional, por lo tanto si falla, la cadena que asignamos no cambia (como si nada hubiera sucedido).

More about Exception Guarantees.

estoy un poco desanimado de que un C++ tutorial promovería dicho código dudosa, rezar me dicen que es un ejemplo de lo que no debe hacer:/

+0

@Jerry: buen punto, lo editaré en. –