2011-12-31 12 views
7

Recibo algunos errores muy extraños. El compilador parece querer llamar al constructor de copias por alguna razón que no entiendo.Error extraño: ¿por qué el compilador intenta llamar al constructor de copia?

(118) std::map<int, layer> xs; 
(119) xs.begin()->first; // error?! 

layer es un no copiables, de tipo móvil.

class layer : public observable 
{ 
    layer(const layer&); 
    layer& operator=(const layer&); 
public: 
    layer(int index = -1); 
    layer(layer&& other); 
    layer& operator=(layer&& other); 
    //... 
}; 

Por alguna razón la línea 119 causó el compilador para tratar de invocar el constructor de copia para std::pair, ¿por qué?

1>c:\program files (x86)\microsoft visual studio 10.0\vc\include\utility(131): error C2248: 'layer::layer' : cannot access private member declared in class 'layer' 
1> ..\layer.h(55) : see declaration of 'layer::layer' 
1> ..\layer.h(53) : see declaration of 'layer' 
1> c:\program files (x86)\microsoft visual studio 10.0\vc\include\utility(129) : while compiling class template member function 'std::_Pair_base<_Ty1,_Ty2>::_Pair_base(const std::_Pair_base<_Ty1,_Ty2> &)' 
1> with 
1> [ 
1>  _Ty1=const int, 
1>  _Ty2=layer 
1> ] 
1> c:\program files (x86)\microsoft visual studio 10.0\vc\include\utility(174) : see reference to class template instantiation 'std::_Pair_base<_Ty1,_Ty2>' being compiled 
1> with 
1> [ 
1>  _Ty1=const int, 
1>  _Ty2=layer 
1> ] 
1> ..\stage.cpp(119) : see reference to class template instantiation 'std::pair<_Ty1,_Ty2>' being compiled 
1> with 
1> [ 
1>  _Ty1=const int, 
1>  _Ty2=layer 
1> ] 

También he intentado lo siguiente, donde falla de manera similar.

(118) std::map<int, layer> xs; 
(119) auto& t1 = *xs.begin(); 
(120) auto& t2 = t1.first; // error?! 

¿Qué está pasando aquí?

+0

¿Por qué iba a necesitar eso? Solo estoy leyendo el valor de la variable miembro "primero". – ronag

+0

'layer (int index = -1);' ya es un constructor público por defecto. –

+1

Ok, entonces quizás el problema sea el constructor de copia privada, verifique esto: http://stackoverflow.com/questions/1440287/how-to-create-a-container-of-noncopyable-elements El primer error indica claramente que un intento de acceder layer :: layer falla porque es privado. – Yaniro

Respuesta

2

Ésta es una de las extrañas sutilezas de errores de plantilla. El código de plantilla no es un código, está casi más cerca de un lenguaje de scripting para generar código. Incluso puede tener un error de sintaxis en una función que no generará necesariamente un error de compilación hasta que el código use esa función (directa o indirectamente).

En este caso xs.first() provocó la generación de std :: map < int, layer> :: iterator, que también necesita la generación de std :: pair < int, layer>. La implementación predeterminada de std :: pair tiene un constructor de copia, que no se puede compilar.

Puede solucionar esto con una especialización de plantilla de std :: pair que no tiene el constructor de copia, pero luego no puede insertar nada en su mapa. xs [0] = myLayer crea e inserta std :: make_pair < 0, myLayer> en su mapa, lo que obviamente requiere la construcción de una capa.

Las soluciones típicas para esto es cambiar el tipo std :: mapa < int, std :: shared_ptr < capa>>. Copiar un shared_ptr no copia el objeto al que se hace referencia.

-1

Depende de dónde inicialice este miembro y su primer miembro. Si lo inicializa como un miembro estático o en la pila sin llamar al constructor, intentará llamar al contructor predeterminado (sin parámetros) y no podrá acceder a él ya que lo ha hecho de forma privada.

Tienes que llamar explícitamente al constructor público para los elementos en el mapa

+0

¿Le importaría al bajista elaborar? – Giel

+0

No fui yo, pero el constructor predeterminado es 'public'. –

-1

Su ejemplo:

(118) std::map<int, layer> xs; 
(119) xs.begin()->first; // error?! 

por http://www.cplusplus.com/reference/stl/map/

xs.begin() Return iterator to beginning 

... IT-> primero; // igual que (* IT) .First (el valor de clave)

Por lo tanto

xs.begin()->first; 

es equivalente a

pair<int,layer> piltmp = (*xs.begin()); 
piltmp.first; 

Et voila. Se ha creado una copia del par en el mapa. Lo cual implica crear una copia de la capa.

(Esto no sería un problema si el mapa celebró punteros o autopointers a capa, en lugar de una capa de sí mismo.)

Ahora, esto no estaría sucediendo si mapa :: :: iterador del operador> devuelto una referencia value_type, en lugar de un value_type. Es decir. si devolvió un lvalue en lugar de un valor r. Parece extraño que no sea así, pero no me he abierto camino a través del estándar.

Es posible conseguir alrededor de él haciendo

pair<int,layer>& piltmp = *xs.begin(); 
return piltmp.first; 

(no evaluados.)

+0

No, 'xs.begin() -> first' es equivalente a' std :: map :: iterator it (xs.begin()); it-> primero; '. El iterador apunta a un 'std :: pair ' y no a un 'layer'. – rve

+0

Bastante justo. El primer ejemplo se convierte en piltmp = (* xs.begin(); piltmp.first. Sí, fue un error en mi ejemplo, pero el punto sigue siendo: aparentemente hay una copia del par en el mapa, y el par contiene una capa, por lo que se está copiando la capa. Si fuera una referencia, un valor l, no habría ningún problema /// Lo cual me recuerda: el posero de la pregunta podría considerar hacer que el mapa se mantenga , no capas, sino punteros o autoproms a capas. –

+0

En su ejemplo, tiene razón en que se hace una copia. Pero su ejemplo no es lo mismo que 'xs.begin() -> first'. Es equivalente a' pair & tmp (* xs.begin()); tmp.first; '. El iterador se copia y no a lo que apunta el iterador.' operator *() 'en el iterador devuelve una referencia al elemento en el mapa que es un' std :: pair '. Y' operator ->() 'en el iterador devuelve un puntero al elemento en el mapa y no un' value_type' como mencionas en tu respuesta. – rve

Cuestiones relacionadas