2011-12-11 34 views
11

Digamos que tengoVector de estructuras con miembros de const?

#include <string> 
#include <vector> 
using namespace std; 

struct Student 
{ 
    const string name; 
    int grade; 
    Student(const string &name) : name(name) { } 
}; 

¿Cómo, entonces, guardo un vector de los estudiantes?

int main() 
{ 
    vector<Student> v; 

    // error C2582: 'operator =' function is unavailable in 'Student' 
    v.push_back(Student("john")); 
} 

¿Hay incluso una manera de hacer esto, o tengo que asignar todos los estudiantes en el montón, y almacenar un puntero a cada uno de ellos en su lugar?

+0

Esto parece compilar y vincular con VC 2010. ¿Puede proporcionar más información sobre su entorno? ¿Es este un caso de prueba completo que reproduce esa falla de compilación? – DRH

+0

@DRH: Estoy en VC 2008, lo siento. Y sí, ese es todo el caso de prueba. – Mehrdad

+0

Mientras que para otras operaciones necesitaría el operador de asignación, no puedo pensar en ninguna posible razón por la cual 'push_back' tendría ese requisito ... de nuevo, es posible que la implementación verifique el requisito' Asignable'. –

Respuesta

7

No puede. Su tipo infringe el requisito de "Asignación" para contenedores estándar.

ISO/IEC 14882: 2003 23.1 [lib.container.requirements]/3:

El tipo de objetos almacenados en estos componentes deben cumplir los requisitos de CopyConstructible tipos (20.1.3), y los requisitos adicionales de Assignable tipos.

De la tabla 64 (Assignable requisitos):

En la Tabla 64, T es del tipo utilizado para instanciar el contenedor, t es un valor de T, y u es un valor de (posiblemente const) T.

expresión: t = u; tipo de devolución: T; post-condición: t es equivalente a u

En teoría, un std::vector equivalente podría optar por hacer la destrucción y construcción copia en todos los casos, pero ese no es el contrato que ha sido elegido. Si no se requiere la reasignación, entonces usar el operador de asignación del tipo contenido para cosas como vector::operator= y vector::assign puede ser significativamente más eficiente.

+0

Oh eh ... ¿así que tiene que ser asignable incluso si nunca asigno nada? No lo sabía – Mehrdad

+0

@Philipp: en realidad, el vector no asigna nada al reasignar. Típicamente solo copia o mueve el nuevo rango y luego elimina el anterior. –

+0

Hmm ... ¿Por qué 'vector' realiza asignaciones de copia? ¿No puede copiar construcción + destrucción, en lugar de usar 'operator ='? – Mehrdad

8

La respuesta simple es: no se puede. Si tiene variables de miembro const, entonces el compilador no puede suministrar un operador predeterminado de copia-asignación. Sin embargo, muchas de las operaciones que proporciona el std::vector necesitan realizar asignaciones y, por lo tanto, requieren un operador (público) de asignación de copias.

Las opciones son:

  1. Hacer name no const.
  2. Escriba su propio operador de asignación de copia, y piense en una forma de lidiar con la "copia" de un miembro const.
1

Los elementos de los vectores deben poder copiarse, y su estructura Student no se debe al miembro const. Simplemente use string name en lugar de const string name. A menos que tenga un requisito específico, los miembros constantes en las clases rara vez son útiles. Si desea evitar cambios en el miembro, hágalo privado y agregue una función getter pública.

3

A vector a menudo necesita mover elementos alrededor.Cada vez que un vector necesita crecer cuando llama al push_back(), reasigna la memoria para mantenerse contigua y copia todos los elementos existentes en el nuevo espacio. Además, si llama a insert() o remove(), los elementos deben cambiarse. Para que vector pueda hacer todo lo que los elementos deben ser copiables, lo que significa que el tipo que almacena en el vector debe tener definido el operador de asignación.

Generalmente, si define una clase, el compilador generará el operador de asignación para esa clase. Sin embargo, hay casos en que el compilador no puede hacer eso. Uno de estos casos es cuando la clase tiene miembros constantes (tenga en cuenta que los punteros a const están bien).

Entonces, en su caso, el problema es el const string name. Impide que el compilador genere operator=(), lo que a su vez impide que se compile vector, aunque usted no use realmente la asignación en sus elementos.

Una solución es hacer name no const. El otro es escribir su propio Student::operator=(), de alguna manera que tenga sentido. La tercera forma es, como ha señalado, utilizar un vector de punteros en lugar de un vector de objetos. Pero luego debe manejar su asignación y desasignación.

P.S. El otro caso cuando el compilador no puede generar operator= es cuando su clase tiene miembros que son referencias.

Cuestiones relacionadas