Search code examples
c++stliteratorpass-by-referencemultimap

Get the content of returned multimap iterator


I am returning multimap iterator from called function.

code:

std::multimap<int,std::string>::iterator it = dst.begin();

     for(int count = 0;count<3 && it !=dst.end();++it,++count)
       std::cout<<it->second<<":"<<it->first<<std::endl;

     return it;  

And calling function:

std::multimap<int,std::string>::const_iterator rec;
    rec= client(); 

    for(int count = 0;count<3 ;++count)
       std::cout<<rec->second<<":"<<rec->first<<std::endl; // Prints garbage values

Here Why I could not print content of rec directly? In called function std::cout<<it->second<<":"<<it->first<<std::endl; prints correct value!

Entire code:

#include<iostream>
#include<algorithm>
#include<map>
#include<vector>

std::multimap<int,std::string>::iterator client()  
{

    std::vector<std::string> most { "lion","tiger","kangaroo",
                                     "donkey","lion","tiger",
                                     "lion","donkey","tiger"
                                     };
    std::map<std::string, int> src;
    for(auto x:most)
        ++src[x];

    std::multimap<int,std::string,std::greater<int> > dst;

    std::transform(src.begin(), src.end(), std::inserter(dst, dst.begin()), 
                       [] (const std::pair<std::string,int> &p) {
                       return std::pair<int,std::string>(p.second, p.first);
                       }
                     );

    std::multimap<int,std::string>::iterator it = dst.begin();

    for(int count = 0;count<3 && it !=dst.end();++it,++count)
        std::cout<<it->second<<":"<<it->first<<std::endl;

    return it;  
}

int main()
{

    std::multimap<int,std::string>::const_iterator rec;
    rec= client(); 

    for(int count = 0;count<3 ;++count,++rec)
    std::cout<<rec->second<<":"<<rec->first<<std::endl;

}

Solution

  • You cannot return iterator to local object, it becomes invalid when you return from function and local object multimap dst is destroyed. You need another design, maybe create object on the free store (return sharedpointer?) or make it static, or pass by reference like this:

    std::multimap<int,std::string>::iterator 
              client(std::multimap<int,std::string,std::greater<int> >& dst) {
    
        std::vector<std::string> most { "lion","tiger","kangaroo",
                                         "donkey","lion","tiger",
                                         "lion","donkey","tiger"
                                         };
        std::map<std::string, int> src;
        for(auto x:most)
            ++src[x];
    
        std::transform(src.begin(), src.end(), std::inserter(dst, dst.begin()), 
                           [] (const std::pair<std::string,int> &p) {
                           return std::pair<int,std::string>(p.second, p.first);
                           }
                         );
    
        std::multimap<int,std::string>::iterator it = dst.begin();
    
         for(int count = 0;count<3 && it !=dst.end();++it,++count)
           std::cout<<it->second<<":"<<it->first<<std::endl;
    
         return dst.begin();  
        } 
    

    usage:

    int main(){
        std::multimap<int,std::string,std::greater<int> > dst;
        std::multimap<int,std::string>::const_iterator rec;
        rec = client(dst);
    
        for(int count = 0;count<3 ;++count,++rec)
           std::cout<<rec->second<<":"<<rec->first<<std::endl;
    
    return 0;
    }
    

    Note: also return dst.begin() not it, because otherwise you might face undefined behavior: it might point out of range because it was incremented before return in client().