Reference loss per parameter

0

I'm having the following problem, when I run the insereOP() method, the instances maq and cli lose their data.

So when I call the atualizarOP method, the client and machine information does not exist, generating an error in the SQL command.

    ClienteDAO cliDAO(con);
    Cliente * cli = cliDAO.getCliente(3);
    MaquinaDAO maqDAO(con);
    Maquina * maq = maqDAO.getMaquina(1);
    OrdemDeProducao tmp("op001",cli,maq,1,10000,QDate(2014,9,1));
    OrdemDeProducaoDAO dialogDAO(con);
    if (dialogDAO.insereOP(tmp)){
        std::cout << "Inserido" << std::endl;
        tmp.setQuantidadeProgramada(50000);
        if(dialogDAO.atualizaOP(tmp)) {
            std::cout << "Atualizado" << std::endl;
        }
    }

Methods used:

Maquina *MaquinaDAO::getMaquina(int codigoMaquina) {
    Maquina * retorno = NULL;
    if(db.open()) {
        query = QSqlQuery(db);
        query.prepare("SELECT CodigoMaquina, NomeMaquina, StatusMaquina FROM Maquina WHERE CodigoMaquina = ?");
        query.addBindValue(codigoMaquina);
        if(!query.exec()){
            std::cout << query.lastError().text().toStdString() << std::endl;
            db.close();
            return retorno;
        } else {
            if (query.first())
                retorno = new Maquina(query.value(0).toInt(), query.value(1).toString(), query.value(2).toInt());
        }
        db.close();
    } else {
        std::cout << db.lastError().text().toStdString() << std::endl;
    }
    return retorno;
}

Cliente *ClienteDAO::getCliente(int codigoCliente) {
    Cliente * retorno = NULL;
    if(db.open()) {
        query = QSqlQuery(db);
        query.prepare("SELECT CodigoCliente, NomeCliente FROM Clientes WHERE CodigoCliente = ?");
        query.addBindValue(codigoCliente);
        if(!query.exec()){
            std::cout << query.lastError().text().toStdString() << std::endl;
            db.close();
            return retorno;
        } else {
            if (query.first())
                retorno = new Cliente(query.value(0).toInt(), query.value(1).toString());
        }
        db.close();
    } else {
        std::cout << db.lastError().text().toStdString() << std::endl;
    }
    return retorno;
}

bool OrdemDeProducaoDAO::insereOP(OrdemDeProducao op) {
    if(db.open()) {
        query = QSqlQuery(db);
        query.prepare("INSERT INTO OrdemdeProducao (op, CodigoCliente, CodigoMaquina, ordem, QuantidadeProgramada, datadeentrega) VALUES (?,?,?,?,?,?)");
        query.addBindValue(op.getOP());
        query.addBindValue(op.getCliente()->getCodigoCliente());
        query.addBindValue(op.getMaquina()->getCodigoMaquina());
        query.addBindValue(op.getOrdem());
        query.addBindValue(op.getQuantidadeProgramada());
        query.addBindValue(op.getDataDeEntrega());
        if(!query.exec()){
            std::cout << query.lastError().text().toStdString() << std::endl;
            db.close();
            return false;
        }
        db.close();
        return true;
    } else {
        std::cout << db.lastError().text().toStdString() << std::endl;
        return false;
    }
}

All project files can be found in the GitHub repository: link

What could be causing this loss of information?

    
asked by anonymous 10.09.2014 / 15:11

1 answer

0

The type OrdemDeProducao is created from pointers given to it in the constructor and deallocates these pointers in the destructor.

Your specific problem occurs when you copy an object of type OrdemDeProducao because you have not implemented a copy constructor or an assignment operator. When this occurs the compiler generates a default version of them for you that simply copies each field of the class.

In your case the effect of these generated functions will be that at the end of the copy two objects of type OrdemDeProducao will point to the same objects of type Cliente and Maquina . This is a problem since the two copies have tried to delete the pointers they save when they are destroyed, causing the other copy to lose the objects it is pointing at.

This problem occurs precisely in the call of the OrdemDeProducaoDAO::insereOP function that receives as a parameter a copy of a OrdemDeProdução . At the end of the execution of this function the op parameter will be destroyed, calling its destructor that will delete the internal pointers of the object. When returning to the main function its tmp object will be with its internal pointers pointing to objects already deleted, thus generating the problem by using them in the OrdemDeProducaoDAO::atualizaOP function.

To solve this problem you have to decide if OrdemDeProducao takes control over the pointers passed to it in the constructor or just observes its state.

If the goal of OrdemDeProducao is just to save references to the client and the machine that are objects under control of another structure, you should not delete the pointers when they are destroyed because they are not under your responsibility and will be deleted by the other structure. So, just remove your constructor as the program will work.

If the goal of OrdemDeProducao is to take control under the Cliente and Maquina objects passed as a parameter then you should think about what happens when you copy an object of this type. The two most common options are:

  • Objects of type OrdemDeProducao when copied should create new copies of the elements pointed to by their pointers.

    OrdemDeProducao::OrdemDeProducao(const OrdemDeProducao& op)
    {
      this->cliente = new Cliente(*op.cliente);
      this->maquina = new Maquina(*op.maquina);
    }
    
    OrdemDeProducao& OrdemDeProducao::operator=(const OrdemDeProducao& op)
    {
      this->cliente = new Cliente(*op.cliente);
      this->maquina = new Maquina(*op.maquina);
    }
    
  • Objects of type OrdemDeProducao should not be copied.

    // Declare o construtor de cópia e o operador de atribuição
    // como privados para que o compilador gere uma
    // mensagem de erro quando forem utilizados. (pré C++11)
    class OrdemDeProducao
    {
      private:
      OrdemDeProducao::OrdemDeProducao(const OrdemDeProducao& op);
      OrdemDeProducao& OrdemDeProducao::operator=(const OrdemDeProducao& op);
    
      // Resto das definições das declarações da classe
      // ...
    };
    
  • If you choose the second option, you will have to modify all functions that are received by value as objects parameter of type OrdemDeProducao so that they receive the same as references, constants or not depending on the case. So, your OrdemDeProducaoDAO::insereOP function would change to:

    bool OrdemDeProducaoDAO::insereOP(const OrdemDeProducao& op);
    
        
    11.09.2014 / 15:57