How to iterate over an STL map full of lines in C ++

I have the following problem related to iterating over an associative array of strings defined using std :: map.

-- snip -- class something { //... private: std::map<std::string, std::string> table; //... } 

In the constructor, I populate the table with pairs of string keys associated with string data. Elsewhere, I have a toString method that returns a string object containing all the keys and its associated data contained in the table object (as key = data format).

 std::string something::toString() { std::map<std::string, std::string>::iterator iter; std::string* strToReturn = new std::string(""); for (iter = table.begin(); iter != table.end(); iter++) { strToReturn->append(iter->first()); strToReturn->append('='); strToRetunr->append(iter->second()); //.... } //... } 

When I try to compile, I get the following

error: "error: no match for call to" (std :: basic_string, std :: allocator>) () ".

Can someone explain to me what is missing, what am I doing wrong? I just found some discussion of a similar problem in the case of hash_map, where the user must define a hash function in order to be able to use hash_map with std :: string objects. Maybe something similar in my case?

Thank!

+61
c ++ iterator stl map
Jun 30 '09 at 23:51
source share
8 answers

The main problem is that you are calling a method called first() in an iterator. What you have to do is use the first property:

 ...append(iter->first) rather than ...append(iter->first()) 

As a style, you should not use new to create this line.

 std::string something::toString() { std::map<std::string, std::string>::iterator iter; std::string strToReturn; //This is no longer on the heap for (iter = table.begin(); iter != table.end(); ++iter) { strToReturn.append(iter->first); //Not a method call strToReturn.append("="); strToReturn.append(iter->second); //.... // Make sure you don't modify table here or the iterators will not work as you expect } //... return strToReturn; } 

edit: facildelembrar indicated (in the comments) that in modern C ++ you can rewrite the loop

 for (auto& item: table) { ... } 
+72
Jul 01 '09 at 0:00
source share
  • Do not write the toString() method. This is not Java. Deploy the stream operator for your class.

  • Prefer to use standard algorithms to write your own loop. In this situation, std::for_each() provides a nice interface to what you want to do.

  • If you must use a loop but are not going to modify the data, prefer const_iterator over iterator . That way, if you accidentally try to change the values, the compiler will warn you.

Then:

 std::ostream& operator<<(std::ostream& str,something const& data) { data.print(str) return str; } void something::print(std::ostream& str) const { std::for_each(table.begin(),table.end(),PrintData(str)); } 

Then, when you want to print it, just place the object:

 int main() { something bob; std::cout << bob; } 

If you really need a string representation of the object, you can use lexical_cast .

 int main() { something bob; std::string rope = boost::lexical_cast<std::string>(bob); } 

Details to be completed.

 class somthing { typedef std::map<std::string,std::string> DataMap; struct PrintData { PrintData(std::ostream& str): m_str(str) {} void operator()(DataMap::value_type const& data) const { m_str << value.first << "=" << value.second << "\n"; } private: std::ostream& m_str; }; DataMap table; public: void something::print(std::ostream& str); }; 
+19
Jul 01 '09 at 0:15
source share

Change your uploads to add

 ...append(iter->first) 

and

 ... append(iter->second) 

In addition, the line

 std::string* strToReturn = new std::string(""); 

selects a row on the heap. If you intend to actually return a pointer to this dynamically allocated string, the return should be changed to std :: string *.

Alternatively, if you do not want to worry about managing this object on the heap, change the local declaration to

 std::string strToReturn(""); 

and change the "add" calls to use the reference syntax ...

 strToReturn.append(...) 

instead

 strToReturn->append(...) 

Remember that this will build a string on the stack and then copy it to the returned variable. This has performance implications.

+4
Jul 01 '09 at 0:01
source share

iter->first and iter->second are the variables that you are trying to name them as methods.

+2
Jun 30 '09 at 23:59
source share

Note that the result of dereferencing std :: map :: iterator is std :: pair . The values โ€‹โ€‹of first and second are not functions, they are variables.

Edit:

 iter->first() 

to

 iter->first 

Same thing with iter->second .

+2
Jul 01 '09 at 0:02
source share

Using:

 std::map<std::string, std::string>::const_iterator 

instead:

 std::map<std::string, std::string>::iterator 
0
Apr 26 '13 at 8:51
source share

in c ++ 11 you can use

 for ( auto iter : table ) { key=iter->first(); value=iter->second(); } 
0
Jan 19 '14 at 0:52
source share

Another worthy optimization is the c_str () member of the STL string classes, which returns an immutable zero-terminated string that can be passed as LPCTSTR , for example. for example, to a user function waiting for LPCTSTR. Although I did not trace through the destructor to validate it, I suspect that the string class is looking for the memory in which it creates a copy.

0
Sep 07 '14 at 0:37
source share



All Articles