I have a map<string, std::function<void(AgentMessage&)>> (AgentMessage is a struct with a few strings). When I try to access it using an iterator I get an access violation on the copy function of pair.
note: The std::function is pointing at a function in a different dll than the place where it is copied.
EDIT: I thought the explanation was good enough for a simple piece of code, but still - here it is.
for (map<string, std::function<void(AgentMessage&)>>::iterator it = mapRef.begin(); it != mapRef.end(); it++)
{
auto functionCopy = it->second; // IT CRASHES HERE
}
Can you show the code that inserts elements to the map?
I tried this and it works:
#include <functional>
#include <map>
#include <string>
using namespace std;
struct AgentMessage
{
};
void f(AgentMessage& am)
{
}
void g(AgentMessage& am)
{
}
int main()
{
AgentMessage am;
map<string, std::function<void(AgentMessage&)>> m;
m["f"] = f;
m["g"] = g;
for (map<string, std::function<void(AgentMessage&)>>::iterator it = m.begin(); it != m.end(); ++it)
{
auto func = it->second;
func(am);
}
}
Related
I was unsure about whether STL containers are entirely copied when passed. First, it worked (so the "fluttershy" element didn't get added, that was good). Then I wanted to track the construction and destruction of entries....
#include <vector>
#include <string>
#include <cstdio>
#include <cstdlib>
using namespace std;
int nextid = 0;
class Entry {
public:
string data;
int myid;
Entry(string in) {
data = in;
myid = nextid;
nextid++;
printf("Entry%02d\n", myid);
}
~Entry() { printf("~Entry%02d\n", myid); }
};
class Meep {
public:
vector<Entry> stuff;
};
void think(Meep m) {
m.stuff.push_back(Entry(string("fluttershy")));
}
int main() {
Meep a;
a.stuff.push_back(Entry(string("applejack")));
think(a);
vector<Entry>::iterator it;
int i = 0;
for (it=a.stuff.begin(); it!=a.stuff.end(); it++) {
printf("a.stuff[%d] = %s\n", i, (*it).data.c_str());
i++;
}
return 0;
}
Produces the following unexpected output( http://ideone.com/FK2Pbp ):
Entry00
~Entry00
Entry01
~Entry00
~Entry01
~Entry00
~Entry01
a.stuff[0] = applejack
~Entry00
That a has only one element is expected, that is not the question. What seriously confuses me is how can one entry be destructed several times ?
What you're seeing is the destruction of temporary instances.
a.stuff.push_back(Entry(string("applejack")));
This line creates a temporary instance which is then copied to another new instance in the container. Then the temporary is destroyed. The instance in the container is destroyed when the entry is removed or the container is destroyed.
I need to write to a bunch of files simultaneously, so I decided to use map <string, ofstream>.
map<string, ofstream> MyFileMap;
I take a vector<string> FileInd, which consists of, say "a" "b" "c", and try to open my files with:
for (vector<string>::iterator it = FileInd.begin(); iter != FileInd.end(); ++it){
...
MyFileMap[*it].open("/myhomefolder/"+(*it)+".");
}
I get the error
request for member 'open' in ..... , which is of non-class type 'std::ofstream*'
I've tried to switch to
map<string, ofstream*> MyFileMap;
But it didn't work either.
Could anyone help?
Thanks.
Clarification:
I've tried both
map<string, ofstream> MyFileMap;
map<string, ofstream*> MyFileMap;
with both
.open
->open
neither of 4 variants work.
Solution (suggested in Rob's code below):
Basically, I forgot "new", the following works for me:
map<string, ofstream*> MyFileMap;
MyFileMap[*it] = new ofstream("/myhomefolder/"+(*it)+".");
std::map<std::string, std::ofstream> can't possibly work, because std::map requires its data type to be Assignable, which std::ofstream isn't. In the alternative, the data type must be a pointer to ofstream -- either a raw pointer or a smart pointer.
Here is how I would do it, using C++11 features:
#include <string>
#include <map>
#include <fstream>
#include <iostream>
#include <vector>
int main (int ac, char **av)
{
// Convenient access to argument array
std::vector<std::string> fileNames(av+1, av+ac);
// If I were smart, this would be std::shared_ptr or something
std::map<std::string, std::ofstream*> fileMap;
// Open all of the files
for(auto& fileName : fileNames) {
fileMap[fileName] = new std::ofstream("/tmp/xxx/"+fileName+".txt");
if(!fileMap[fileName] || !*fileMap[fileName])
perror(fileName.c_str());
}
// Write some data to all of the files
for(auto& pair : fileMap) {
*pair.second << "Hello, world\n";
}
// Close all of the files
// If I had used std::shared_ptr, I could skip this step
for(auto& pair : fileMap) {
delete pair.second;
pair.second = 0;
}
}
and the 2nd verse, in C++03:
#include <string>
#include <map>
#include <fstream>
#include <iostream>
#include <vector>
int main (int ac, char **av)
{
typedef std::map<std::string, std::ofstream*> Map;
typedef Map::iterator Iterator;
Map fileMap;
// Open all of the files
std::string xxx("/tmp/xxx/");
while(av++,--ac) {
fileMap[*av] = new std::ofstream( (xxx+*av+".txt").c_str() );
if(!fileMap[*av] || !*fileMap[*av])
perror(*av);
}
// Write some data to all of the files
for(Iterator it = fileMap.begin(); it != fileMap.end(); ++it) {
*(it->second) << "Hello, world\n";
}
// Close all of the files
for(Iterator it = fileMap.begin(); it != fileMap.end(); ++it) {
delete it->second;
it->second = 0;
}
}
I am just trying to declare a map iterator but I get a compile error saying "expected ; before it"
I believe it is because I haven't included the whole std namespace (using namespace std;) but I intentionally dont want to include all of it.
My code:
#include <map>
#include <string>
template <class Object>
class Cont
{
public:
Cont() {}
Object* get( unsigned int nID )
{
std::map <unsigned int, Object*>::iterator it = m.begin(); // error here "expected ; before it" what is this error?
for ( ; it != m.end(); it++ )
{
if ( (*it).second->ID == nID ) { return (*it).second; }
}
return NULL;
}
std::map <unsigned int, Object*> m;
};
I have tried this aswell but it doesn't work:
std::map <unsigned int, Object*>::std::iterator it = m.begin();
If I'm not mistaken because you are using a template argument you need to prefix the iterator declaration with typename.
typename std::map <unsigned int, Object*>::iterator it = m.begin();
What's your compiler and flag settings? I was able to build this OK.
// test.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <map>
#include <string>
class Foo
{
public:
int ID;
};
template <class Object> class Cont
{
public:
Cont() {}
Object* get( unsigned int nID )
{
std::map <unsigned int, Object*>::iterator it = m.begin(); // error here "expected ; before it" what is this error?
for ( ; it != m.end(); it++ )
{
if ( (*it).second->ID == nID ) { return (*it).second; }
}
return NULL;
}
std::map <unsigned int, Object*> m;
};
int _tmain(int argc, _TCHAR* argv[])
{
Cont<Foo> c;
c.get( 2 );
return 0;
}
You don't say what compiler you're using, but just by cutting and pasting this into a new file, it compiles fine in VS2010. You don't need to using namespace std; certainly....
(And your wrinkle of putting another std:: before iterator was creative, but isn't correct. :-) You're specifying that the map class template is located in namespace std::, and iterator is a type that's nested within the map template.)
I want to traverse an STL map. I don't want to use its key. I don't care about the ordering, I just look for a way to access all elements it contains. How can I do this?
Yes, you can traverse a Standard Library map. This is the basic method used to traverse a map, and serves as guidance to traverse any Standard Library collection:
C++03/C++11:
#include <cstdlib>
#include <map>
#include <string>
using namespace std;
int main()
{
typedef map<int,string> MyMap;
MyMap my_map;
// ... magic
for( MyMap::const_iterator it = my_map.begin(); it != my_map.end(); ++it )
{
int key = it->first;
string value = it->second;
}
}
If you need to modify the elements:
Use iterator rather than const_iterator.
Instead of copying the values out of the iterator, get a reference and modify the values through that.
for( MyMap::iterator it = my_map.begin(); it != my_map.end(); ++it )
{
int key = it->first;
string& value = it->second;
if( value == "foo" )
value = "bar";
}
This is how you typically traverse Standard Library containers by hand. The big difference is that for a map the type of *it is a pair rather than the element itself
C++11
If you have the benefit of a C++11 compiler (for example, latest GCC with --std=c++11 or MSVC), then you have other options as well.
First you can make use of the auto keyword to get rid of all that nasty verbosity:
#include <cstdlib>
#include <map>
#include <string>
using namespace std;
int main()
{
map<int,string> my_map;
// ... magic
for( auto it = my_map.begin(); it != my_map.end(); ++it )
{
int key = it->first;
string& value = it->second;
}
}
Second, you can also employ lambdas. In conjunction with decltype, this might result in cleaner code (though with tradeoffs):
#include <cstdlib>
#include <map>
#include <string>
#include <algorithm>
using namespace std;
int main()
{
map<int,string> my_map;
// ... magic
for_each(my_map.begin(), my_map.end(), [](decltype(*my_map.begin()) val)
{
string& value = val.second;
int key = val.first;
});
}
C++11 also instroduces the concept of a range-bases for loop, which you may recognize as similar to other languages. However, some compilers do not fully support this yet -- notably, MSVC.
#include <cstdlib>
#include <map>
#include <string>
#include <algorithm>
using namespace std;
int main()
{
map<int,string> my_map;
// ... magic
for(auto val : my_map )
{
string& value = val.second;
int key = val.first;
}
}
As with any STL container, the begin() and end() methods return iterators that you can use to iterate over the map. Dereferencing a map iterator yields a std::pair<const Key, Value>.
C++17
Since C++17 you can use range-based for loops together with structured bindings for iterating over a map. The resulting code, e.g. for printing all elements of a map, is short and well readable:
std::map<int, std::string> m{ {3, "a"}, {5, "b"}, {9, "c"} };
for (const auto &[k, v] : m)
std::cout << "m[" << k << "] = " << v << std::endl;
Output:
m[3] = a
m[5] = b
m[9] = c
Code on Coliru
You can traverse STL map in the same way as any other STL container: using iterators, e.g.
for (std::map<key, value>::const_iterator
i = myMap.begin(), end = myMap.end(); i != end; ++i)
{
// *i is a key-value pair
}
Using for with auto for C++11 and above usage
map<int,int> map_variable; //you can use any data type for keys, as well as value
for(auto &x:map_variable)
{
cout<<x.first ;// gives the key
cout<<x.second; //gives the value
}
The newer format of for using auto was introduced in C++11
To give it functionality like some higher level languages like python
Where there was already an implementation of such type of iteration
P.S. : map variable keeps values sorted, so when iterating you will get keys in sorted order
You can iterate map by using auto iterator.
Code Snippet:
#include<bits/stdc++.h>
using namespace std;
int main()
{
ios::sync_with_stdio(false);
map<string, int> mp;
mp["a"]=500;
mp["b"]=200;
mp["d"]=300;
mp["c"]=400;
for(auto it=mp.begin(); it != mp.end(); it++)
{
cout<<it->first <<" : "<<it->second<<endl;
}
return 0;
}
I am trying to print the contents of the map and this is where my code fails. I have tested all my methods and I have no problem to read from file, filer the word, put it into map, and even the print function is working.
However, when I am calling the printer function from main it does not print the map.
I am new to polymorphism and I think that my error is in how I am passing the map to the function in main.
Here is my main class:
using namespace std;
#include <iostream>
#include "ReadWords.h"
#include "ReadPunctWords.h"
#include "ReadNumWords.h"
#include "ReadCapWords.h"
#include "MapWorks.h"
#include <fstream>
#include <string>
#include <map>
#include <iterator>
/**
* This main function uses all other classes.
*/
int main() {
char* name = "RomeoJuliet.txt";
//ReadPunctWords &obj = *new ReadPunctWords(name);
ReadPunctWords obj(name);
string startSearch="BEGIN";
string endSearch="FINIS";
ReadPunctWords rpw;
ReadCapWords rcw;
ReadNumWords rnw;
MapWorks mw;
while(rpw.isNextWord()){
string tempword = obj.getNextWord();
if(tempword == startSearch){
break;
}
}
while(rpw.isNextWord()){
string tempword = obj.getNextWord();
if(tempword == endSearch){
break;
}
else{
if(rpw.filter(tempword)){
mw.addToMap(tempword, mw.mapPunct);
}
if(rcw.filter(tempword)){
mw.addToMap(tempword, mw.mapCap);
}
if(rnw.filter(tempword)){
mw.addToMap(tempword, mw.mapNum);
}
}
}
mw.printMap(mw.mapPunct);
mw.printMap(mw.mapCap);
mw.printMap(mw.mapNum);
//clear map
mw.clearMap(mw.mapPunct);
mw.clearMap(mw.mapCap);
mw.clearMap(mw.mapNum);
//close the file
//obj.close();
//delete &obj;
//exit(0); // normal exit
return 0;
}
And my MapWorks.cpp which contains the maps and the functions related to maps:
using namespace std;
#include <iostream>
#include <string>
#include <map>
#include <iterator>
#include "MapWorks.h"
/**
* MapWorks class builds the maps and does the map processing and printing
*/
MapWorks::MapWorks() {}
void MapWorks::addToMap(string myword, map<string, int> & myMap){
int n = myMap[myword];
myMap[myword]= n+1;
}
void MapWorks::printMap (map<string, int> &myMap){
for (map<string, int>::iterator it = myMap.begin(); it != myMap.end(); ++it)
{
cout << it->first << " ==> " << it->second << '\n'<<endl;
}
}
//delete entries in map
void MapWorks::clearMap(map<string, int>myMap) {
myMap.clear();
}
MapWorks.h :
#ifndef MAPWORKS_H
#define MAPWORKS_H
#include <string>
#include <map>
using namespace std;
/**
* MapWorks class builds the maps and does the map processing and printing
*/
class MapWorks {
public:
map<string, int> mapPunct; //(word, number of occurences)
map<string, int> mapNum; //(word, number of occurences)
map<string, int> mapCap; //(word, number of occurences)
MapWorks();
void addToMap(string myword, map<string, int> & myMap); //adds words to a map
void printMap (map<string, int> &myMap); //prints the map
void clearMap(map<string, int>); //clear map
};
#endif
My ReadWords.h :
/**
* ReadWords class, the base class for ReadNumWords, ReadPunctWords, ReadCapWords
*/
#ifndef READWORDS_H
#define READWORDS_H
using namespace std;
#include <string>
#include <fstream>
#include<iostream>
class ReadWords
{
private:
string nextword;
ifstream wordfile;
bool eoffound;
public:
/**
* Constructor. Opens the file with the default name "text.txt".
* Program exits with an error message if the file does not exist.
*/
ReadWords();
/**
* Constructor. Opens the file with the given filename.
* Program exits with an error message if the file does not exist.
* #param filename - a C string naming the file to read.
*/
ReadWords(char *filename);
/**
* Closes the file.
*/
void close();
/**
* Returns a string, being the next word in the file.
* #return - string - next word.
*/
string getNextWord();
/**
* Returns true if there is a further word in the file, false if we have reached the
* end of file.
* #return - bool - !eof
*/
bool isNextWord();
//pure virtual function for filter
virtual bool filter(string word)=0;
/**
* Fix the word by the definition of "word"
* end of file.
* #return - string
*/
string fix(string word);
};
#endif
And my ReadPunctWords (ReadNumWords and ReadCapWords are quite the same, just checking if the word has digits or capital letters instead of punctuations like in here):
#ifndef READPUNCTWORDS_H
#define READPUNCTWORDS_H
using namespace std;
#include <string>
#include "ReadWords.h"
/**
* ReadPunctWords inherits ReadWords, so MUST define the function filter.
* It chooses to override the default constructor.
*/
class ReadPunctWords: public ReadWords {
public:
ReadPunctWords();
ReadPunctWords(char *filename): ReadWords(filename){};
virtual bool filter(string word);
};
#endif
I would appreciate any help from you.
Thanks, Adriana
There are a number of things that are potential issues in your code, but the most obvious thing that may be causing the printMap not to work as expected is this while loop.
map<string, int>::iterator it = myMap.begin();
cout<<"test"<<endl;
while(it!=myMap.end()){
cout<<(*it).first<<" ==> "<<(*it).second<<endl;
}
Nowhere do you increment the iterator so either nothing will be printed (if the map is empty) or else the first item will printed over and over again and the loop won't terminate.
The idiomatic way to write this loop would be as a for loop.
for (std::map<string, int>::iterator it = myMap.begin(); it != myMap.end(); ++it)
{
std::cout << it->first << " ==> " << it->second << '\n';
}
The other issue is that your addToMap function probably isn't working as intended because you pass the map to the function by value and this means that the map that the function is adding an item to is actually a copy of the map that was passed in.
When control is passed to the calling function this copy is destroyed and the map that was passed it is still empty.
To pass a map by reference you need to add & to the type of the parameter in the function declaration.
i.e. in the headfile, the the MapWorks class definition:
void addToMap(string myword, map<string, int>& myMap);
and in the source file:
void MapWorks::addToMap(string myword, map<string, int>& myMap)
{
// definition...
}
Your use of references for dynamically allocated objects is unusual, to say the least. For your purposes, I don't see any point to doing:
ReadWords &rnw = *new ReadNumWords();
when you delete the object at the end of the same function in which it is created. You can just do this (exactly as you do with MapWorks mw;).
ReadNumWords rnw;
If you have to use dynamically allocated objects, just using pointers rather than references is much more usual but it is highly recommended to use some sort of a smart pointer so that you don't have to remember to call delete explicitly.
You forgot to increment iterator:
while(it!=myMap.end()){
cout<<(*it).first<<" ==> "<<(*it).second<<endl;
// you forgot this:
it++;
}
And, more importantly, consider few modifications to your code:
// ReadPunctWords &obj = *new ReadPunctWords(name);
// should likely be:
ReadPunctWords obj(name);
// same applies to other 'newed' 'references'
// and then there's no need to do
// delete &obj;
// exit(0); // normal exit
// should probably be just a
return 0;
// obj.close();
// can be called in the destructor of ReadPunctWords class
// and RAII will help you get your file closed correctly when needed
// void MapWorks::printMap (map<string, int>myMap)
// should better be:
void MapWorks::printMap (const std::map<string, int> &myMap)
// same applies to other functions in your code
// here's how your commented-out function could look like
void MapWorks::printMap(const std::map<string, int> &myMap) {
typedef std::map<string, int>::iterator mapsi;
for (mapsi m = myMap.begin(); m != myMap.end(); ++m) {
std::cout << (*m).first << " ==> " << (*m).second << "\n";
}
}
// void MapWorks::addToMap(string myword, map<string, int>myMap)
// should be:
void MapWorks::addToMap(std::string myword, std::map<string, int> &myMap)
If possible, I'd suggest breaking the logic up into slightly smaller units, and pushing more of the logic into the classes -- right now, main does quite a lot more than I'd like to see there, and (particularly) knows more about the internals of the classes than I'd like to see either.
If I were doing it, I'd start with a map that knew how to filter out words, so it can only accept what it's supposed to:
class Map {
std::map<std::string, int> counts;
public:
struct Filter {
virtual bool operator()(std::string const &) const = 0;
};
Map(Filter const &f) : filter(f) {}
bool InsertWord(std::string const &word) {
return filter(word) && (++counts[word] != 0);
}
friend std::ostream &operator<<(std::ostream &os, Map const &m) {
std::copy(m.counts.begin(),
m.counts.end(),
std::ostream_iterator<count>(std::cout, "\n"));
return os;
}
private:
Filter const &filter;
};
Then we'd need some derivatives of Filter to do the real filtering. These probably don't work the way you really want; they're really just placeholders:
struct Num : Map::Filter {
bool operator()(std::string const &w) const {
return isdigit(w[0]) != 0;
}
};
struct Punct : Map::Filter {
bool operator()(std::string const &w) const {
return ispunct(w[0]) != 0;
}
};
struct Letter : Map::Filter {
bool operator()(std::string const &w) const {
return isalpha(w[0]) != 0;
}
};
Then MapWorks can delegate almost all the real work to the Map (which in turn uses a Filter):
class MapWorks {
Map num;
Map punct;
Map letter;
public:
// For the moment, these allocations just leak.
// As long as we only create one MapWorks object,
// they're probably not worth fixing.
MapWorks()
: num(Map(*new Num())),
punct(Map(*new Punct())),
letter(Map(*new Letter()))
{}
// Try adding the word until we find a Map
// that accepts it.
bool push_back(std::string const &word) {
return num.InsertWord(word)
|| punct.InsertWord(word)
|| letter.InsertWord(word);
}
// Write out by writing out the individual Map's:
friend std::ostream &operator<<(std::ostream &os, MapWorks const &m) {
return os << m.num << "\n" << m.punct << "\n" << m.letter << "\n";
}
};
With these in place, main becomes pretty simple: (though for the moment, I've just had it read a whole file instead of looking for "BEGIN" and "FINIS"):
int main() {
MapWorks m;
std::string temp;
while (std::cin >> temp)
m.push_back(temp);
std::cout << m;
return 0;
}
There are a few other bits and pieces, such as typedef'ing the count type and defining an inserter for it, but they're pretty minor details.