[SOLUCIONADO] C++ - Error con memoria dinámica: ¿Puntero por referencia?

Iniciado por xaps, 21 Noviembre 2013, 01:21 AM

0 Miembros y 1 Visitante están viendo este tema.

xaps

Dadas dos funciones, necesito pasar un puntero por referencia de una función a la otra para obtener los datos de una lista de strings (las dos funciones están dentro de la misma clase).
El problema viene dado a que desde un objeto de esa clase, necesito acceder a datos privados de otro objeto del mismo tipo (una lista de strings). Entonces, la solución más eficiente que se me ha ocurrido es crear un puntero de tipo vector<string> vect, pasarlo por referencia a la otra función, y en esa hacer vect = new vector<string> (N), donde N es el tamaño de la lista de la que quiero obtener sus elementos, pero me da errores de compilación y no consigo resolverlos.

Os adjunto el código de las dos funciones implicadas y el error recibido al compilar (compilo en Linux con G++):

NOTA: La primera función empieza en la línea 33, y la segunda en la línea 71, por lo que los errores saltan en las líneas marcadas con el comentario ERROR EN ESTA LÍNEA.

Código (cpp) [Seleccionar]

#include <vector>
#include <list>

list<string> lista; //Esto está declarado en la parte privada de la clase

void Objeto::fusion_objeto(const Objeto &rev)
{
 //Declaro puntero
 vector<string> *s = NULL;
 rev.func_aux(s);
 int n = s->size();
 for (int i = 0; i < n; ++i) lista.insert(lista.begin(), s[i]); //ERROR EN ESTA LÍNEA
 delete s;
}

void Objeto::func_aux(vector<string>* &s)
{
 int N = lista.size();
 s = new vector<string> (N);
 list<string>::iterator it = lista.begin();
 for (int i = 0; i < N; ++i)
 {
   s[i] = *it; //ERROR EN ESTA LÍNEA
   ++it;
 }
}


Error de la primera función:

Objeto.cpp: In member function 'void Objeto::fusion_objeto(const Objeto&)':
Objeto.cpp:39:69: error: no matching function for call to 'std::list<std::basic_string<char> >::insert(std::list<std::basic_string<char> >::iterator, std::vector<std::basic_string<char> >&)'
Objeto.cpp:39:69: note: candidates are:
In file included from /usr/include/c++/4.7/list:65:0,
                from Objeto.hpp:8,
                from Objeto.cpp:1:
/usr/include/c++/4.7/bits/list.tcc:99:5: note: std::list<_Tp, _Alloc>::iterator std::list<_Tp, _Alloc>::insert(std::list<_Tp, _Alloc>::iterator, const value_type&) [with _Tp = std::basic_string<char>; _Alloc = std::allocator<std::basic_string<char> >; std::list<_Tp, _Alloc>::iterator = std::_List_iterator<std::basic_string<char> >; std::list<_Tp, _Alloc>::value_type = std::basic_string<char>]
/usr/include/c++/4.7/bits/list.tcc:99:5: note:   no known conversion for argument 2 from 'std::vector<std::basic_string<char> >' to 'const value_type& {aka const std::basic_string<char>&}'
In file included from /usr/include/c++/4.7/list:64:0,
                from Objeto.hpp:8,
                from Objeto.cpp:1:
/usr/include/c++/4.7/bits/stl_list.h:1104:7: note: void std::list<_Tp, _Alloc>::insert(std::list<_Tp, _Alloc>::iterator, std::list<_Tp, _Alloc>::size_type, const value_type&) [with _Tp = std::basic_string<char>; _Alloc = std::allocator<std::basic_string<char> >; std::list<_Tp, _Alloc>::iterator = std::_List_iterator<std::basic_string<char> >; std::list<_Tp, _Alloc>::size_type = long unsigned int; std::list<_Tp, _Alloc>::value_type = std::basic_string<char>]
/usr/include/c++/4.7/bits/stl_list.h:1104:7: note:   candidate expects 3 arguments, 2 provided
/usr/include/c++/4.7/bits/stl_list.h:1125:9: note: template<class _InputIterator> void std::list::insert(std::list<_Tp, _Alloc>::iterator, _InputIterator, _InputIterator) [with _InputIterator = _InputIterator; _Tp = std::basic_string<char>; _Alloc = std::allocator<std::basic_string<char> >]
/usr/include/c++/4.7/bits/stl_list.h:1125:9: note:   template argument deduction/substitution failed:
Objeto.cpp:39:69: note:   candidate expects 3 arguments, 2 provided



Error de la segunda función:

Objeto.cpp: In member function 'void Objeto::func_aux(std::vector<std::basic_string<char> >*&)':
Objeto.cpp:78:13: error: no match for 'operator=' in '*(s + ((sizetype)(((long unsigned int)i) * 24ul))) = it.std::_List_iterator<_Tp>::operator*<std::basic_string<char> >()'
Objeto.cpp:78:13: note: candidate is:
In file included from /usr/include/c++/4.7/vector:70:0,
                from Objeto.hpp:9,
                from Objeto.cpp:1:
/usr/include/c++/4.7/bits/vector.tcc:161:5: note: std::vector<_Tp, _Alloc>& std::vector<_Tp, _Alloc>::operator=(const std::vector<_Tp, _Alloc>&) [with _Tp = std::basic_string<char>; _Alloc = std::allocator<std::basic_string<char> >]
/usr/include/c++/4.7/bits/vector.tcc:161:5: note:   no known conversion for argument 1 from 'std::basic_string<char>' to 'const std::vector<std::basic_string<char> >&'


Tiene pinta de que acceda mal a las posiciones del vector dinámico. He probado con lo siguiente, pero lógicamente no funciona.
*(s[i])

¿Alguna idea?

Saludos y gracias
"The programmers of tomorrow are the wizards of the future" - Gave Newel

amchacon

Muy abstracto *_*

CitarEl problema viene dado a que desde un objeto de esa clase, necesito acceder a datos privados de otro objeto del mismo tipo (una lista de strings). Entonces, la solución más eficiente que se me ha ocurrido es crear un puntero de tipo vector<string> vect, pasarlo por referencia a la otra función
C++ te permite el uso de variables "referencia". Son más seguras y más naturales que los punteros:

Código (cpp) [Seleccionar]
int cosa = 0;
int &objeto = cosa;

cout<<objeto<<endl;

cosa = 1;

cout<<objeto<<endl;


No entiendo bien tú código pero un vector se puede copiar con el constructor copia:

Código (cpp) [Seleccionar]
vector<string> tuVector(otroVector);

Si usas un puntero, tendrías que poner eso en el new. Pero repito que no necesitas punteros para nada.


Por otro lado si quieres insertar un elemento al principio, te vendría mejor push_front:
http://www.cplusplus.com/reference/list/list/push_front/


Por favor, no me manden MP con dudas. Usen el foro, gracias.

¡Visita mi programa estrella!

Rar File Missing: Esteganografía en un Rar

xaps

#2
Cita de: amchacon en 21 Noviembre 2013, 12:15 PM
Muy abstracto *_*
C++ te permite el uso de variables "referencia". Son más seguras y más naturales que los punteros:

Código (cpp) [Seleccionar]
int cosa = 0;
int &objeto = cosa;

cout<<objeto<<endl;

cosa = 1;

cout<<objeto<<endl;


...

Por otro lado si quieres insertar un elemento al principio, te vendría mejor push_front:
http://www.cplusplus.com/reference/list/list/push_front/

Al ser parte de un trabajo de la universidad, tengo varias restricciones. Entre ellas, están no poder hacer funciones que retornen tipos complejos (como lo son vectores o listas), no poder usar ciertos métodos (push_front lo tenemos prohibido tanto en listas como vectores) y el uso de & lo tengo restringido para pasar parametros por referencia en las funciones. Los métodos no deberian cambiar por temas de restricciones como ya he dicho. Lo ideal sería encontrar el problema con el puntero sin cambiar la estructura de las funciones.

Cita de: amchacon en 21 Noviembre 2013, 12:15 PM
No entiendo bien tú código pero un vector se puede copiar con el constructor copia:

Código (cpp) [Seleccionar]
vector<string> tuVector(otroVector);

Si usas un puntero, tendrías que poner eso en el new. Pero repito que no necesitas punteros para nada.

Estoy intentando pasar el contenido de una lista a un vector, por lo que el uso del constructor-copia de <vector> no serviría para este caso.

Si hay algo que no entiendes de mi código coméntalo y intentaré explicártelo lo mejor que pueda. Lo mejor para estos temas es que todos los que nos involucremos aprendamos algo nuevo.

Saludos
"The programmers of tomorrow are the wizards of the future" - Gave Newel

lapras

El segundo argumento de lista.insert() debería ser un número.
Además de eso, dado que s es un puntero debes acceder los elementos así:
Código (cpp) [Seleccionar]
(*s)[i]
en vez de así:
Código (cpp) [Seleccionar]
s[i]
Otra cosa es que no tiene sentido pasar un puntero por referencia:
Código (cpp) [Seleccionar]
vector<string>* &s

xaps

Cita de: lapras en 21 Noviembre 2013, 14:16 PM
El segundo argumento de lista.insert() debería ser un número.
Además de eso, dado que s es un puntero debes acceder los elementos así:
Código (cpp) [Seleccionar]
(*s)[i]
en vez de así:
Código (cpp) [Seleccionar]
s[i]
Otra cosa es que no tiene sentido pasar un puntero por referencia:
Código (cpp) [Seleccionar]
vector<string>* &s

El segundo parametro del insert no debería ser un número, ya que la lista se ha declarado como lista de string.

En cuanto a la solución dada, funciona, muchas gracias. No sé como no se me había pasado por la cabeza esto... Supongo que por la poca experiencia que tengo en memoria dinámica.

Una duda:

*s[i]

Esto no me funcionaba porque lo cogía todo como un puntero, ¿verdad? Es decir, como si fuera un vector de punteros.

Y la segunda parte en la que me dices que no tiene sentido pasar un puntero por referencia, supongo que es porque aunque se cree una copia del puntero, la posición de memoria a la que apunta será modificada igualmente, ¿cierto? Por lo que el puntero de la primera función ya apuntará al valor modificado.

Saludos
"The programmers of tomorrow are the wizards of the future" - Gave Newel

lapras

Tienes razón en lo del insert, fallo mío.

Lo del puntero es por el tema de las precedencias, el operador [] es el que tiene más precedencia junto con otros. Entonces esto *s es equivalente a esto *(s).
Como bien has dicho, lo que haces es coger un elemento e intentas usarlo como si fuese un puntero.

Lo de pasar un puntero por referencia lo digo porque los parametros que se pasan por refrencia suelen ser estructuras de tamaño considerable.  Eso es porque copiar dicha estructura sería muy costoso. En realidad pasar algo por referencia es como pasar un puntero a ese algo, sólo que dentro de la función no necesitas hacer tantos castings(queda feo tanto paréntesis), y además al llamar a la función pasas el parametro como si fuese por valor(te ahorras el &). Volviendo a lo de pasar un puntero por referencia, un puntero ocupa poco, no necesitas pasar una refencia a un puntero(es como si pasas un puntero a un puntero). No esta mal aunque si lo pasas por valor ahorras un acceso a memoria.

xaps

Cita de: lapras en 21 Noviembre 2013, 23:05 PM
Tienes razón en lo del insert, fallo mío.

Lo del puntero es por el tema de las precedencias, el operador [] es el que tiene más precedencia junto con otros. Entonces esto *s es equivalente a esto *(s).
Como bien has dicho, lo que haces es coger un elemento e intentas usarlo como si fuese un puntero.

Lo de pasar un puntero por referencia lo digo porque los parametros que se pasan por refrencia suelen ser estructuras de tamaño considerable.  Eso es porque copiar dicha estructura sería muy costoso. En realidad pasar algo por referencia es como pasar un puntero a ese algo, sólo que dentro de la función no necesitas hacer tantos castings(queda feo tanto paréntesis), y además al llamar a la función pasas el parametro como si fuese por valor(te ahorras el &). Volviendo a lo de pasar un puntero por referencia, un puntero ocupa poco, no necesitas pasar una refencia a un puntero(es como si pasas un puntero a un puntero). No esta mal aunque si lo pasas por valor ahorras un acceso a memoria.

Muchas gracias por la explicación, me has resuelto la duda.

Saludos
"The programmers of tomorrow are the wizards of the future" - Gave Newel

lapras