Search code examples
c++qt-creatorstdstdstringoutofrangeexception

std::out_of_range while setting a QLineEdit


In my C++ application, I have to select a file with the QFileDialog class. Then, I verify that my file name is correct (it has to start by "VG").

My file has this structure : VGx-xx-xxxx-xxx-xxx.pigs

After what, I set it in the associate QLineEdit. But each time I select a good file, it crashes, and I don't understand why.

Here are my different function :

OPEN THE QFILE DIALOG WINDOW

/** OPEN FILE DIALOG WINDOW  **/
void VGCCC::selectPIGSFile()
{
    QString pigsFile = QFileDialog::getOpenFileName
    (
        this,
        tr("Select PIGS file"),
        "./../VGCColorConfigurator/Inputs",
        tr("Document files (*.pigs *.igs)"),
        0,
        QFileDialog::DontUseNativeDialog
    );

    pigsPath = pigsFile;
    if(verifyPIGSFileValidity(pigsPath.toStdString()))
    {
        m_filePathLine->setText("");
        m_filePathLine->setText(pigsPath);
        m_testTextEdit->insertPlainText("File selected : "+pigsPath+"\n");
    }
    else
    {
        m_filePathLine->setText("Please select a valid PIGS (Format VGx-xx-xxxx-xxx-xxx.pigs)");
        m_testTextEdit->insertPlainText("Uncorrect PIGS file.\n");
    }
}

VERIFICATION OF THE FILE NAME

/** VERIFY SELECTED PIG FILE **/
bool VGCCC::verifyPIGSFileValidity(std::string pigsPath)
{
    splitPIGSName(pigsPath);
    std::string verification = pigsNameTable[0].erase(2,2);
    std::string headerName = "VG";

    if(!verification.compare(headerName))
    {
        m_testTextEdit->insertPlainText("PIGS name is correct");
        return true;
    }
    else
        return false;
}

SPLIT METHOD

/** SPLIT PIGS NAME INTO TABLE **/
std::string* VGCCC::splitPIGSName(std::string pigsPath)
{
    std::string pigsPathToSplit = pigsPath;
    std::string delimiter = "-";
    size_t position = 0;
    int i=0;
    std::string token;

    while ((position = pigsPathToSplit.find(delimiter)) != std::string::npos)
    {
        token = pigsPathToSplit.substr(0, position);
        std::cout << token << std::endl;
        pigsNameTable[i] = token;
        i++;
        pigsPathToSplit.erase(0, position + delimiter.length());
    }
    pigsNameTable[4] = pigsPathToSplit.c_str();
    std::cout << pigsPathToSplit << std::endl;
}

Solution

  • bool VGCCC::verifyPIGSFileValidity(std::string pigsPath)
    {
        splitPIGSName(pigsPath);
        std::string verification = pigsNameTable[0].erase(2,2);
        std::string headerName = "VG";
    
        if(!verification.compare(headerName))
        {
            m_testTextEdit->insertPlainText("PIGS name is correct");
            return true;
        }
        else
            return false;
    }
    

    Is unsafe because:

    1- You don't check if pigsNameTable has an element at index (if a vector?) or key (if a map?) 0

    2- You don't check that pigsNameTable[0] has more than 2 elements. See erase documentation:

    pos: Position of the first character to be erased. If this is greater than the string length, it throws out_of_range.

    You could simply do:

    bool VGCCC::verifyPIGSFileValidity(std::string pigsPath)
    {
        splitPIGSName(pigsPath);
    
        if ( /* test is pigsNameTable[0] exists depending on pigsNameTable's type */ )
        {
            return pigsNameTable[0].find( "VG" ) == 0; // return true if pigsNameTable[0] starts with "VG"
        }
        else
        {
            return false;
        }
    }
    

    If pigsNameTable is a vector the test can be !pigsNameTable.empty(), if it's a map, pigsNameTable.find(0) != pigsNameTable.end()....