2011-12-31 7 views
8

Vea el siguiente código: Estoy tratando de poner un objeto const en un vector. Sé que la respuesta es "Los contenedores STL requieren objetos para ser asignables y copiar constructables", pero, sin citar el estándar, ¿alguien puede explicar cuál es el problema al hacer esto? No entiendo por qué una clase como esta no pudo ser copiada (además de que C++ no lo permite).¿Por qué no puedes poner un objeto const en un contenedor STL?

Todo lo que tiene es un valor almacenado que no puede cambiarse. ¿Por qué no ponerlo en un vector simplemente crea otro de estos objetos?

#include <vector> 

// Attempt 1 
// /home/doriad/Test/Test.cxx:3:8: error: non-static const member ‘const int MyClass::x’, can’t use default assignment operator 

// struct MyClass 
// { 
// int const x; 
// MyClass(int x): x(x) {} 
// }; 
// 
// int main() 
// { 
// std::vector<MyClass> vec; 
// vec.push_back(MyClass(3)); 
// return 0; 
// } 

// Attempt 2 
// /home/doriad/Test/Test.cxx:28:23: error: assignment of read-only member ‘MyClass::x’ 
struct MyClass 
{ 
    int const x; 
    MyClass(int x): x(x) {} 
    MyClass& operator= (const MyClass& other) 
    { 
    if (this != &other) 
    { 
     this->x = other.x; 
    } 

    return *this; 
    } 
}; 

int main() 
{ 
    std::vector<MyClass> vec; 
    vec.push_back(MyClass(3)); 
    return 0; 
} 

EDIT:

Es posible hacer esto con std :: set y std :: lista. Supongo que es la función sort() en std :: vector que usa la asignación. Esto no es UB ¿verdad?

#include <set> 

// Attempt 1 
struct MyClass 
{ 
    int const x; 
    MyClass(int x): x(x) {} 
    bool operator< (const MyClass &other) const; 
}; 

bool MyClass::operator<(const MyClass &other) const 
{ 
    if(this->x < other.x) 
    { 
    return true; 
    } 
    else if (other.x < this->x) 
    { 
    return false; 
    } 

} 


int main() 
{ 
    std::set<MyClass> container; 
    container.insert(MyClass(3)); 
    return 0; 
} 
+0

Semirelacionado: http://stackoverflow.com/questions/2759350/embarassing-c-question-regarding-const/2759426#2759426 – cHao

+0

Consulte mi edición usando std :: set en lugar de std :: vector. ¿Esta bien? –

+0

@David: en C++ 03, el uso de 'std :: set <>' como tal todavía está mal formado, el §23.1/3 establece que los tipos de elementos deben ser tanto constructables como de copia y asignables. En C++ 11, su código está bien formado, pero su instancia 'std :: set <>' no será asignable porque 'MyClass' no es asignable. (Además, solo semi-relacionado: su implementación 'operator '' está rota, ya que no devolverá ningún valor si 'this-> x == other.x'). – ildjarn

Respuesta

6

Edit2: (Extracción de un montón de cosas que no tienen que trabajar) Los C++ 11 estados estándar que el método de insertvector y deque (y la implementación predeterminada de push_back para el caso) requiere el tipo de valor que sea CopyAssignable, es decir, el valor es compatible con:

t= v; 

clases y las estructuras con const miembros no CopyAssignable son por defecto, por lo que quiere hacer no va a funcionar.

Este documento (n3173) tiene una explicación para los diversos requisitos del contenedor.

+2

MSN: entonces, ¿qué tengo que hacer para que funcione? Me obligó a implementar el operador de asignación, pero no puedo hacer la tarea porque es const! –

+1

@David: simplemente evite los miembros de datos const - son inútiles si su clase ofrece getters correctos const. – ildjarn

+2

Eso parece un truco, no es lo "correcto" que hay que hacer. –

0

Cuando coloca un objeto de tipo MyClass en el archivo std :: vector, el vector hará una copia del objeto para el almacenamiento, y no el objeto que le pasó.

+1

Claro, eso tiene sentido. ¿Pero por qué no puede copiar un objeto con un valor constante? Debería ser capaz de hacer un nuevo objeto con el mismo valor de constricción, ¿no? –

+0

@David: Claro, pero aún te falta el requisito de 'asignable'. – ildjarn

1

Una posible solución sería almacenar punteros a los objetos en el vector, ya que los punteros son asignables y copiables constructables.

Otra posible solución sería declarar x sin la palabra clave const, pero asegurarse de que no se puede modificar a través de la encapsulación (es decir, se debe declarar como privado y no se modifican desde cualquier lugar fuera del constructor) ..

Cuestiones relacionadas