Problem with STL map iterator copying - c++

I have an STL map that I want to iterate through, and can't seem to get the code to work. The code is:
//PowerupInfo is a struct defined in this class's header file
std::map<std::string, PowerupInfo> powerups;
...populate powerups
std::map<std::string, PowerupInfo>::iterator iter;
for (iter = powerups.begin(); iter != powerups.end(); iter++) {
return iter->second.type ;
}
The error message I get is:
error: no match for 'operator=' in 'iter = (((const std::map<std::string, PowerupInfo, std::less<std::string>, std::allocator<std::pair<const std::string, PowerupInfo> > >)((const PowerupList)this)) + 24u)->std::map<_Key, _Tp, _Compare, _Alloc>::begin with _Key = std::string, _Tp = PowerupInfo, _Compare = std::less<std::string>, _Alloc = std::allocator<std::pair<const std::string, PowerupInfo> >'|
note: candidates are: std::_Rb_tree_iterator<std::pair<const std::string, PowerupInfo> >& std::_Rb_tree_iterator<std::pair<const std::string, PowerupInfo> >::operator=(const std::_Rb_tree_iterator<std::pair<const std::string, PowerupInfo> >&)|
So I would normally assume that the problem has to do with setting iter equal to something it doesn't like, as it's not finding a match for 'operator='. But why? Why wouldn't that assignment work?
EDIT:
Turns out the method WAS const, causing the reference to powerups to be const as well, causing the error. I was just doing a bad job reading my own code. Thanks guys!

Your map name is poweruplist not powerups (You are using this name in the for loop). If this is not the cause of the error, then it looks like you are for loop is in a function which accepts the map by const reference (or is a const member function of a class). In that case your type of iterator should be const_iterator and not iterator.

Reformatting error code to make it readable:
error: no match for 'operator=' in
'iter =
((
(const std::map<std::string, PowerupInfo>*)((const PowerupList*)this)
)
+ 24u
)->std::map<std::string, PowerupInfo>::begin()'
Does not look the error message to the code you supplied.
Please cut and past the code. Otherwise it is meaningless.

Related

Error with map and string conversion in c++

I'm familiar with Python's dictionary function, and I'm assuming based on my research that C++'s map function is relatively similar. However I'm running into a "conversion" issue:
std::string dictionary(std::string inquiry){
std::map<std::string, std::string> mapK;
mapK["12th st. Oakland City Center"]="12th";
mapK["16th st. Mission"]="16th";
return mapK.find(inquiry);
}
This is a string function that should receive a string and then with the corresponding key return a string back to the main. Evidently there's an issue with the return statement.
error: could not convert 'mapK.std::map<_Key, _Tp, _Compare, _Alloc>::find<std::basic_string<char>, std::basic_string<char>, std::less<std::basic_string<char> >, std::allocator<std::pair<const std::basic_string<char>, std::basic_string<char> > > >((*(const key_type*)(& inquiry)))' from 'std::map<std::basic_string<char>, std::basic_string<char> >::iterator {aka std::_Rb_tree_iterator<std::pair<const std::basic_string<char>, std::basic_string<char> > >}' to 'std::string {aka std::basic_string<char>}'
return mapK.find(inquiry);
std::map::find() returns iterator, specifically std::map::iterator.
The only thing you need to fix is to put a dereference:
return *mapK.find(inquiry);
Or even better, just use operator[]:
return mapK[inquiry];
Do note though that if inquiry is not in the map, it will return empty string. In case of find, it is straight undefined behavior.
Your problem is with the return type of find. It does not return the mapped type. Rather it returns an iterator.
The signature for find is iterator find( const Key& key ); (see here; there is also the const overload).
You should also check whether the key was found. So you could write something like
MapType::iterator i = mapK.find(inquiry);
if (i != mapK.end())
return i->second;
else
return ""; // or handle error some other way
Alternatively you could use the member access operator[], but this will insert a default constructed element in the map if the key is not found.

Insert value into vector in a list

I have a specific list with vectors. i want to add a value to a vector. How can I do this?
Here is my code:
//creating the list with vectors
std::list< vector<string> > adjacencylist;
//adding some vectors to the list...
adjacencylist.push_back(std::vector<std::string>(1, "String"));
adjacencylist.push_back(std::vector<std::string>(1, "String"));
adjacencylist.push_back(std::vector<std::string>(1, "String"));
Now I want to add values to the vectors in the list...
I tried for this:
std::list< vector<string> >::const_iterator it = adjacencylist.begin();
(*it).push_back("Some more String");
I thought that this would work. So I could iterate over all vectors and insert the values that I want. But it does not work. Here the output of the compiler:
example.cpp: In function ‘int main(int, char**)’:
example.cpp:148:31: error: passing ‘const std::vector<std::basic_string<char> >’ as ‘this’ argument of ‘void std::vector<_Tp, _Alloc>::push_back(const value_type&) [with _Tp = std::basic_string<char>; _Alloc = std::allocator<std::basic_string<char> >; std::vector<_Tp, _Alloc>::value_type = std::basic_string<char>]’ discards qualifiers [-fpermissive]
(*it).push_back("test");
Because you have declared it as a const_iterator you have made it such that what it references cannot be edited. When you call push_back you are attempting to edit the vector that it points to. You need to replace:
std::list< vector<string> >::const_iterator it = adjacencylist.begin();
(*it).push_back("Some more String");
with
std::list< vector<string> >::iterator it = adjacencylist.begin();
(*it).push_back("Some more String");
Read up on general constness here and there is more specific information on const_iterator here.
Use simply an iterator. Also you can use it -> push_back instead of (*it).push_back.
This is an example:
for (list< vector<string> > it = adjacencylist.begin(); it != adjacencylist.end(); ++it)
{
it -> push_back("Your std::string");
}

Inserting strings to vector

I am getting a compilation error. I am trying to add strings to a vector and keep them in "sorted order".
XYZ is my class. addPortEntry
class XYZ
{
public:
portListFile(string sTmp);
void addPortEntry(string sPortName, string sDirection);
private:
string sPortListFileName;
vector <string> v_input_ports;
...
};
void XYZ::addP(string sP, string sDir)
{
if(sDir == "in")
{
v_input_ports.insert(sP); // Line 42
}
...
}
Error:
XYZ.cpp: In member function ‘void XYZ::addP(std::string, std::string)’:
XYZ.cpp:42: error: no matching function for call to ‘std::vector<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::basic_string<char, std::char_traits<char>, std::allocator<char> > > >::insert(const char [10])’
/usr/lib/gcc/x86_64-redhat-linux/4.1.2/../../../../include/c++/4.1.2/bits/vector.tcc:93: note: candidates are: typename std::vector<_Tp, _Alloc>::iterator std::vector<_Tp, _Alloc>::insert(__gnu_cxx::__normal_iterator<typename std::_Vector_base<_Tp, _Alloc>::_Tp_alloc_type::pointer, std::vector<_Tp, _Alloc> >, const _Tp&) [with _Tp = std::basic_string<char, std::char_traits<char>, std::allocator<char> >, _Alloc = std::allocator<std::basic_string<char, std::char_traits<char>, std::allocator<char> > >]
/usr/lib/gcc/x86_64-redhat-linux/4.1.2/../../../../include/c++/4.1.2/bits/stl_vector.h:657: note: void std::vector<_Tp, _Alloc>::insert(__gnu_cxx::__normal_iterator<typename std::_Vector_base<_Tp, _Alloc>::_Tp_alloc_type::pointer, std::vector<_Tp, _Alloc> >, size_t, const _Tp&) [with _Tp = std::basic_string<char, std::char_traits<char>, std::allocator<char> >, _Alloc = std::allocator<std::basic_string<char, std::char_traits<char>, std::allocator<char> > >]
insert should be given an iterator to insert at a certain location. You need to use push_back instead (which is the same as insert with end() as parameter).
edit
You mentioned in the comments:
I do not want to use push_back since I want the strings to be sorted.
That is one of the reasons I'm using the vector
I miss the logic in that statement. If you want a sorted container you should be using either std::set or std::map. Use the "multi-" versions if you want repeating values.
Perhaps you meant push_back rather than insert?
Generally speaking, you can either append an element to a vector
(push_back), or you can insert it at a specified place (insert). To
insert an object at a specified place, you have to specify the place;
std::vector<>::insert takes two arguments, the first an iterator
specifying where, and the second the value to be inserted.
You say you want to maintain the contents in sorted order. The usual
idiom for that is to find the location using std::lower_bound, e.g.:
void
XYZ::addP( std::string const& sP, std::string const& sDir )
{
if ( sDir == "in" ) {
std::vector<std::string>::iterator pos
= std::lower_bound( v_input_ports.begin(),
v_input_ports.end(),
sP );
if ( pos != v_input_ports.end() && *pos == sDir ) {
// Object already present...
*pos = sP; // But maybe an error is more appropriate
} else {
v_input_ports.insert( pos, sP );
}
}
}
Two quick comments, however:
You should probably be passing std::string by const reference,
rather than by value. For whatever reasons, this is the almost
universal convention, and if you don't follow it, people will wonder
why.
Any time you're concerned with order in the standard, you need to
define the ordering relationship. The default is std::less<>, which by
default does <. But functions like std::lower_bound can be passed
an additional argument which defines the order in any way you want
(subject to the constraint that it is a "strict weak ordering"). I
mention this because the way < is defined on std::string is useless
in most cases where you're dealing with actual text, so you may want to
consider defining your own ordering relationship.

copying vector of pair

I am trying to copy a vector of pair to another:
vector<pair<int,int>> vp = {pair<int,int>(1,1), pair<int,int>(2,2)};
vector<pair<int,int>> vp2;
for_each(vp.begin(), vp.end(), [vp2](pair<int,int> p){
if(/*some condition*/){
vp2.push_back(p);
}
});
I get this compiler error:
error: passing ‘const std::vector<std::pair<int, int> >’ as ‘this’ argument of ‘void std::vector<_Tp, _Alloc>::push_back(value_type&&) [with _Tp = std::pair<int, int>, _Alloc = std::allocator<std::pair<int, int> >, value_type = std::pair<int, int>]’ discards qualifiers
Using gcc 4.5.1 on ubuntu.
As an alternative to Konrad's answer; if the goal is simply to copy the elements of the first vector if they match a certain condition, would std::copy_if not be a better match?
vector<pair<int,int>> vp = {pair<int,int>(1,1), pair<int,int>(2,2)};
vector<pair<int,int>> vp2;
copy_if(vp.begin(), vp.end(), back_inserter(vp2), [](pair<int,int> p) { return /* some condition */; });
Copying is much easier than that:
vector<pair<int,int>> vp2(vp.begin(), vp.end());
or even:
vector<pair<int,int>> vp2 = vp; // or
vector<pair<int,int>> vp2(vp);
The error in your code is that you capture vp2 by value which effectively makes it const in your anonymous method, and you cannot call push_back on a const vector. The following should work:
for_each(vp.begin(), vp.end(), [&vp2](pair<int,int> p){vp2.push_back(p);});
But there’s no reason to use this instead of the simpler code.

"Forced constness" in std::map<std::vector<int>,double> >?

Consider this program:
#include <map>
#include <vector>
typedef std::vector<int> IntVector;
typedef std::map<IntVector,double> Map;
void foo(Map& m,const IntVector& v)
{
Map::iterator i = m.find(v);
i->first.push_back(10);
};
int main()
{
Map m;
IntVector v(10,10);
foo(m,v);
return 0;
}
Using g++ 4.4.0, I get his compilation error:
test.cpp: In function 'void foo(Map&, const IntVector&)':
test.cpp:8: error: passing 'const std::vector<int, std::allocator<int> >' as 'this' argument of 'void std::vector<_Tp, _Alloc>::push_back(const _Tp&) [with _Tp = int, _Alloc = std::allocator<int>]' discards qualifiers
I would expect this error if I was using Map::const_iterator inside foo but not using a non-const iterator.
What am I missing, why do I get this error?
The keys in a map are constant. A map is a tree, and you can't just going around changing the keys or you'll break its invariants. The value_type of a map with Key and Value is std::pair<const Key, Value>, to enforce this.
Your design needs some changing. If you really need to modify the key, you need to remove the element, change its key, and re-insert it with the new key.
Also concerning your example specifically, you will get undefined behavior (if this did work). Your map is empty when you call foo, so the iterator returned by find will be m.end(); the element doesn't exist. But then you'd go on to modify this non-existent element: ka-boom. Whenever you find something, you should check that it was found before you attempt to use it.