Problems iterating over a list within a class

3

Let's consider the following code. It has a class that contains a data and a list of elements of the other class, which houses its own data and a pointer of the first type to relate. It would be schematically like this:

struct nodo
{
    dato datonodo;
    std::list<arista>ListaAristas;
};

struct arista
{
    dato2 datoarista;
    nodo* destino;
};

Finally I insert these nodes in a list:

std::list<nodo>lista;

Well, if I directly access a node, and within it to its ListaAristas, I do not have problems, but if it is on the list of nodes, and then, within each element of the list, I try to access your ListAristas, I do not get anything.

This would be an example:

#include <iostream>
#include <list>

struct nombre;
struct relacion
{
    std::string datorelacion;
    nombre* destino;

    relacion(std::string dato):datorelacion(dato) {}
    relacion(const relacion& otro):datorelacion(otro.datorelacion)
    {
        destino = otro.destino;
    }
    relacion operator=(const relacion& otro)
    {
        if (this!=&otro)
        {
            datorelacion=otro.datorelacion;
            destino=otro.destino;
            return *this;
        }
    }
};

struct nombre
{
    //miembros
    std::string datonombre;
    std::list<relacion>ListaRelaciones;
    //metodos
    nombre (std::string dato):datonombre(dato) {}
    nombre (const nombre& otro):datonombre(otro.datonombre), ListaRelaciones(otro.ListaRelaciones){}
    nombre& operator=(const nombre&otro)
    {
        if (this!=&otro)
        {
            datonombre = otro.datonombre;
            ListaRelaciones = otro.ListaRelaciones;
            return *this;
        }
    }       
};

int main()
{
    std::string tipo1="es amigo de ";
    std::string tipo2="es enemigo de ";
    std::string tipo3="es familar de ";
    /***********************************/
    std::list<nombre>listanombres;
    /**********************************/
    nombre N1("Pepe");
    listanombres.push_back(N1);
    /********************************/
    nombre N2("Juan");
    listanombres.push_back(N2);
    /******************************/
    nombre N3("Ana");
    listanombres.push_back(N3);
    /******************************/
    nombre N4("Pepa");
    listanombres.push_back(N4);
    /********RELACIONES************/
    relacion R1(tipo1);
    relacion R2(tipo2);
    relacion R3(tipo3);

    R1.destino = &N2;
    R2.destino = &N3;
    R3.destino = &N4;

    N1.ListaRelaciones.push_back(R1);
    N1.ListaRelaciones.push_back(R2);
    N2.ListaRelaciones.push_back(R3);
    N3.ListaRelaciones.push_back(R3);
/******accedo a un nodo cualquiera de forma directa-->FUNCIONA***********/
    for (const auto& elem : N1.ListaRelaciones)
    {
        std::cout<<N1.datonombre<<" "<<elem.datorelacion<<" "<<elem.destino->datonombre<<"\n";
    }
/******accedo a cada elemento de la lista, y luego intento acceder a la ListaArista de cada uno de ellos--->NO FUNCIONA************/
    for (const auto& elem : listanombres)
    {
        std::cout<<elem.datonombre<<" ";
        for (auto elem2 : elem.ListaRelaciones)
        {
            std::cout<<elem2.datorelacion<<" "<<elem2.destino->datonombre;
        }
        std::cout<<"\n";
    }
    return 0;
}
    
asked by user3733164 14.05.2018 в 23:38
source

1 answer

3

It is normal that it does not work because you are modifying the originals, not the copies that you add to your lists.

When you add elements of type nombre to listanombres ( N1 , N2 , N3 and N4 ) you are copying the elements, when you then alter the names N1 , N2 and N3 adding relationships are not altering the copies within listanombres if not the originals. I have corrected and simplified your code:

struct nombre;
struct relacion
{
    std::string datorelacion{};
    nombre* destino = nullptr;

    relacion(std::string dato): datorelacion(dato) {}
    // Pedimos al compilador genere el constructor de copia.
    relacion(const relacion& otro) = default;
    // El compilador generará el operador de asignación.
};

struct nombre
{
    //miembros
    std::string datonombre{};
    std::list<relacion> ListaRelaciones{};
    //metodos
    nombre (std::string dato):datonombre(dato) {}
    // Pedimos al compilador genere el constructor de copia.
    nombre (const nombre& otro) = default;
    // El compilador generará el operador de asignación.
};

int main()
{
    // Construimos los nombres directamente en la lista
    std::list<nombre> listanombres{ nombre{"Pepe"}, nombre{"Juan"}, nombre{"Ana"}, nombre{"Pepa"} };

    /********RELACIONES************/
    relacion amistad("es amigo de ");
    relacion enemistad("es enemigo de ");
    relacion parentesco("es familar de ");

    auto nombre = ++listanombres.begin(); // Apuntamos a Juan
    amistad.destino = &(*nombre);         // Relación de amistad con el 2º elemento de listanombres (Juan)
    ++nombre;                             // Avanza nombre
    enemistad.destino = &(*nombre);       // Relación de enemistad con el 3r elemento de listanombres (Ana)
    ++nombre;                             // Avanza nombre
    parentesco.destino = &(*nombre);      // Relación de parentesco con el 4º elemento de listanombres (Pepa)

    nombre = listanombres.begin(); // Apuntamos a Pepe
    nombre->ListaRelaciones.push_back(amistad);    // Pepe es amigo de Juan
    nombre->ListaRelaciones.push_back(enemistad);  // Pepe es enemigo de Ana
    ++nombre;                                      // Avanza nombre, ahora somos Juan
    nombre->ListaRelaciones.push_back(parentesco); // Juan es pariente de Pepa
    ++nombre;                                      // Avanza nombre, ahora somos Ana
    nombre->ListaRelaciones.push_back(parentesco); // Ana es pariente de Pepa

    nombre = listanombres.begin(); // Apuntamos a Pepe
    for (const auto& elem : nombre->ListaRelaciones)
    {
        std::cout << nombre->datonombre << ' ' << elem.datorelacion << elem.destino->datonombre << '\n';
    }

    for (const auto& elem : listanombres)
    {
        std::cout << elem.datonombre << ' ';
        for (auto elem2 : elem.ListaRelaciones)
        {
            std::cout << elem2.datorelacion << ' ' << elem2.destino->datonombre << '\n';
        }
    }

    return 0;
}

The most relevant changes are:

  • Using a list iterator to access the elements will be the correct elements since we work with the content of the list, not elements outside it.
  • Copy constructors can be generated by the compiler if we add = default at the end of their declaration. It is necessary to explicitly ask the compiler to do so because creating a constructor disables the other constructors generated by default.
  • We do not implement the assignment operator because we can let the compiler generate it for us without making it explicit.
  • The names of the variables are self-explanatory rather than cryptic.
answered by 15.05.2018 / 12:00
source