简体   繁体   中英

Why I can't call std::mismatch function for the second time?

I use STL's mismatch function to help me to find common directory path. In doing so, I use multimap::equal_range to get range of equal elements.

For my sample program (please see fro you reference), I got a vector vPathWithCommonDir filled with 3 elements such as "C:/MyProg/Raw/", "C:/MyProg/Subset/MTSAT/" and "C:/MyProg/Subset/GOESW/", when iterating the multimap mmClassifiedPaths for the first time. I then passed this vector to FindCommonPath function, and returned a common path "C:/MyProg" what I wanted. When looping for the second time, it's not necessary to call FindCommonPath function because there is only one element. When iterating for the third time, I got a vector vPathWithCommonDir filled with 2 elements, namely "D:/Dataset/Composite/" and "D:/Dataset/Global/". A fatal error occurred when I called FindCommonPath function passed with vPathWithCommonDir for the second time. I could not solve this problem.

Would you please help me? Thank you very much!

// TestMismatch.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"

#include <algorithm> 
#include <map>
#include <vector>
#include <string>

std::string FindCommonPath(const std::vector<std::string> & vDirList, char cSeparator) ;

int _tmain(int argc, _TCHAR* argv[])
{   
std::vector<std::string> vDirList;

// Populate the vector list
vDirList.push_back("C:/XML/");
vDirList.push_back("C:/MyProg/Raw/");
vDirList.push_back("C:/MyProg/Subset/MTSAT/");
vDirList.push_back("C:/MyProg/Subset/GOESW/");
vDirList.push_back("D:/Dataset/Composite/");
vDirList.push_back("D:/Dataset/Global/");
vDirList.push_back("E:/Dataset/Mosaic/");

std::multimap<std::string, std::string> mmClassifiedPaths;

for (std::vector<std::string>::iterator it = vDirList.begin(); it != vDirList.end(); it++)
{   
    std::string sPath = *it;
    std::string::iterator itPos;

    std::string::iterator itBegin = sPath.begin();
    std::string::iterator itEnd = sPath.end();

    // Find the first occurrence of separator '/'
    itPos = std::find( itBegin, itEnd, '/' );

    // If found '/' for the first time
    if ( itPos != itEnd ) 
    {  
       // Advance the current position iterator by at least 1
       std::advance(itPos, 1);

       // Find the second occurrence of separator '/'
       itPos = std::find( itPos, itEnd, '/' );

       // If found '/' for the second time
       if ( itPos != itEnd ) 
       {  
          std::string sFound = sPath.substr(0, itPos - itBegin);
          mmClassifiedPaths.insert( std::pair<std::string, std::string>(sFound, sPath) );
       }
    }
}

//std::multimap<std::string, std::string>::iterator it;
std::vector<std::string> vPathToWatch;
std::pair<std::multimap<std::string, std::string>::iterator,    std::multimap<std::string, std::string>::iterator> pRet;

for (std::multimap<std::string, std::string>::iterator it = mmClassifiedPaths.begin(); 
     it != mmClassifiedPaths.end(); it++)
{   
    size_t nCounter = (int)mmClassifiedPaths.count(it->first);
    pRet = mmClassifiedPaths.equal_range(it->first);

    if (nCounter <= 1)
    {  
       vPathToWatch.push_back(it->second);
       continue;
    }

    std::vector<std::string> vPathWithCommonDir;

    for (std::multimap<std::string, std::string>::iterator itRange = pRet.first; itRange != pRet.second; ++itRange)
    {   
        vPathWithCommonDir.push_back(itRange->second);
    }

    // Find the most common path among the passed path(s)
    std::string strMostCommonPath = FindCommonPath(vPathWithCommonDir, '/');

    // Add to directory list to be watched
    vPathToWatch.push_back(strMostCommonPath);

    // Advance the current iterator by the amount of elements in the 
    // container with a key value equivalent to it->first
    std::advance(it, nCounter - 1);
}

return 0;
}

std::string FindCommonPath(const std::vector<std::string> & vDirList, char cSeparator) 
{   
std::vector<std::string>::const_iterator vsi = vDirList.begin();   
int nMaxCharsCommon = vsi->length();   
std::string sStringToCompare = *vsi;   

for (vsi = vDirList.begin() + 1; vsi != vDirList.end(); vsi++) 
{      
    std::pair<std::string::const_iterator, std::string::const_iterator> p = std::mismatch(sStringToCompare.begin(), sStringToCompare.end(), vsi->begin()); 

    if ((p.first - sStringToCompare.begin()) < nMaxCharsCommon)      
       nMaxCharsCommon = p.first - sStringToCompare.begin();
}

std::string::size_type found = sStringToCompare.rfind(cSeparator, nMaxCharsCommon);

return sStringToCompare.substr( 0 , found ) ;
}   

You have to ensure that there are at least as many items in both iterator ranges provided to mismatch - it does not do any checking.

The fix would be to do a distance check between the ranges and provide the smaller one as the first range and the larger range as second.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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