繁体   English   中英

C++ std::vector push_back 具有奇怪的行为

[英]C++ std::vector push_back with strange behaviour

首先,我对 C 和 C++ 比较陌生,我更习惯于 C#。

基本上,我有一个向量 object,称为 CTe,这个 object 有几个变量和另一个 object 的向量,称为 NFe,我要填充 CTes 对象的所有信息都存储在这个字符串的 2D 向量中循环是遍历向量的所有行,每行一个CTe,这个CTe可能有一个或多个NFes附加到它上面。

    /*The declaration of the vectors, just to help visualize the structure
    vector < string > dirlist;
    vector < vector < string > > listElement;
    vector < CTe > ctes;*/

    //This will iterate through the 2D vector
    for (int i = 1; i < listElement.size(); i++)
    {
        //Temporally CTe object to store information
        CTe temp;

        string targetCNTR = listElement[i][6];
        int countNFE = 0;
        bool haveFoundReference = false;

        // This will iterate reading all the xmls I have in a folder
        for (int j = 2; j < dirlist.size(); j++)
        {
            string extraInfoNFE = ReadXML(dirlist[j], "infAdic", "infCpl");

            //Check if a valid xml was found.
            if (extraInfoNFE.find(targetCNTR) != string::npos)
            {
                haveFoundReference = true;

                string sColeta = "000"+listElement[i][3];
                stringstream tipoNumber (listElement[i][4]);

                //Fill the variables of the temp object
                temp.cntr = targetCNTR.c_str();
                temp.booking = listElement[i][0].c_str();
                temp.motorista = listElement[i][1].c_str();
                temp.placas = listElement[i][2].c_str();
                temp.coleta = sColeta.c_str();
                temp.seqEndereco = listElement[i][5].c_str();
                tipoNumber >> temp.tipoCTE;

                listElement[i][8+countNFE] = ReadXML(dirlist[j], "ide", "nNF");

                //Create a temporally object to store the NFe information
                NFe tempNFe;

                //Fill the tempNFe object
                stringstream nfeNumber (listElement[i][8+countNFE]);
                nfeNumber >> tempNFe.numeroNFE;

                string sXML = dirlist[j].substr(5, 43);
                tempNFe.codigoXML = sXML.c_str();

                string sDest = ReadXML(dirlist[j], "dest", "xNome");
                tempNFe.destinatario = sDest.c_str();

                stringstream cfopNumber (ReadXML(dirlist[j], "det", "prod", "CFOP"));
                cfopNumber >> tempNFe.cfop;

                stringstream qtdeNumber (ReadXML(dirlist[j], "transp", "vol", "qVol"));
                qtdeNumber >> tempNFe.qtde;

                stringstream valorNumber (ReadXML(dirlist[j], "total", "ICMSTot", "vNF"));
                valorNumber >> tempNFe.valor;

                stringstream pesoNumber (ReadXML(dirlist[j], "transp", "vol", "pesoB"));
                pesoNumber >> tempNFe.pesoBruto;

                //push_back the tempNFe into the temp object
                //This part is working perfectly
                temp.notas.push_back(tempNFe);
                countNFE++;
            }
        }

        //Check if a valid xml was found, if so push_back
        //The temp object into the ctes object
        //HERE LIES THE PROBLEM
        if (haveFoundReference)
        {
            cout<<temp.cntr<<" - ";
            ctes.push_back(temp);
        }
        else
        {
            cout << "Não foi possível localizar a nota do CNTR " <<targetCNTR;
        }
    }

问题是,ctes 向量中的所有 CTe 对象都是相同的,唯一有效的是 CTe 内的 NFe 向量。

这是 CTe 和 NFe 类:

NFE

class NFe
{
    public:
        NFe();
        const char* codigoXML;
        const char* destinatario;
        int numeroNFE;
        int cfop;
        int qtde;
        float valor;
        float pesoBruto;
        ~NFe();
};

CTE

#include <nfe.h>
#include <vector>

class CTe
{
    public:
        CTe();
        const char* motorista;
        const char* placas;
        const char* booking;
        const char* cntr;
        const char* seqEndereco;
        const char* coleta;
        int espelho;
        int tipoCTE;
        std::vector < NFe > notas;
        virtual ~CTe();
};

正如我在前面的评论中提到的, c_str()返回的char *仅在相应的字符串 object 被销毁或修改之前有效。 在你的情况下,

string targetCNTR = listElement[i][6];

在向量内创建字符串的副本,并且该副本在退出 for 循环后立即被销毁。 所以

temp.cntr = targetCNTR.c_str();

退出 scope 后targetCNTR被破坏后立即无效。

如果您无法修改 class 定义以将const char *更改为std::string并且如果向量listElement在程序的整个生命周期内保持有效,则可以通过获取对实际字符串的引用来修复代码,如下所示

string &targetCNTR = listElement[i][6];

这样,只要listElement向量未被破坏或修改,返回的c_str()将是有效的。 如果istElement被修改/销毁(您没有提供填充listElement的代码,因此不明显),您还可以像这样创建char *的副本

/* allocate a new char * on heap */
char *cntr = new char [strlen(targetCNTR.c_str()) + 1];
/* copy the c string */
strcpy(cntr, targetCNTR.c_str());
/* move the char * to desired object */
temp.cntr = cntr; 

您可以对所有char *变量执行相同的操作。 如果您使用这种方法,请记住释放 class 析构函数中的char * 例如,

class CTe
{
    public:
        CTe();
        const char* motorista;
        const char* placas;
        const char* booking;
        const char* cntr;
        const char* seqEndereco;
        const char* coleta;
        int espelho;
        int tipoCTE;
        std::vector < NFe > notas;
        virtual ~CTe() {
            /* free char * */
            delete [] motorista;
            delete [] placas;
            delete [] booking;
            delete [] cntr;
            delete [] seqEndereco;
            delete [] coleta;
        }

};

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM