I have a map named valueMap as follows:
typedef std::map<std::string, std::string>MAP;
MAP valueMap;
...
// Entering data.
Then I am passing this map to a function by reference:
void function(const MAP &map)
{
std::string value = map["string"];
// By doing so I am getting an error.
}
How can I get the value from the map, which is passed as a reference to a function?
std::map::operator[] is a non-const member function, and you have a const reference.
You either need to change the signature of function or do:
MAP::const_iterator pos = map.find("string");
if (pos == map.end()) {
//handle the error
} else {
std::string value = pos->second;
...
}
operator[] handles the error by adding a default-constructed value to the map and returning a reference to it. This is no use when all you have is a const reference, so you will need to do something different.
You could ignore the possibility and write string value = map.find("string")->second;, if your program logic somehow guarantees that "string" is already a key. The obvious problem is that if you're wrong then you get undefined behavior.
map.at("key") throws exception if missing key.
If k does not match the key of any element in the container, the
function throws an out_of_range exception.
http://www.cplusplus.com/reference/map/map/at/
The answer by Steve Jessop explains well, why you can't use std::map::operator[] on a const std::map. Gabe Rainbow's answer suggests a nice alternative. I'd just like to provide some example code on how to use map::at(). So, here is an enhanced example of your function():
void function(const MAP &map, const std::string &findMe) {
try {
const std::string& value = map.at(findMe);
std::cout << "Value of key \"" << findMe.c_str() << "\": " << value.c_str() << std::endl;
// TODO: Handle the element found.
}
catch (const std::out_of_range&) {
std::cout << "Key \"" << findMe.c_str() << "\" not found" << std::endl;
// TODO: Deal with the missing element.
}
}
And here is an example main() function:
int main() {
MAP valueMap;
valueMap["string"] = "abc";
function(valueMap, "string");
function(valueMap, "strong");
return 0;
}
Output:
Value of key "string": abc
Key "strong" not found
Code on Ideone
The main problem is that operator[] is used to insert and read a value into and from the map, so it cannot be const.
If the key does not exist, it will create a new entry with a default value in it, incrementing the size of the map, that will contain a new key with an empty string ,in this particular case, as a value if the key does not exist yet.
You should avoid operator[] when reading from a map and use, as was mention before, map.at(key) to ensure bound checking. This is one of the most common mistakes people often do with maps. You should use insert and at unless your code is aware of this fact. Check this talk about common bugs Curiously Recurring C++ Bugs at Facebook
How can I get the value from the map, which is passed as a reference to a function?
Well, you can pass it as a reference. The standard reference wrapper that is.
typedef std::map<std::string, std::string> MAP;
// create your map reference type
using map_ref_t = std::reference_wrapper<MAP>;
// use it
void function(map_ref_t map_r)
{
// get to the map from inside the
// std::reference_wrapper
// see the alternatives behind that link
MAP & the_map = map_r;
// take the value from the map
// by reference
auto & value_r = the_map["key"];
// change it, "in place"
value_r = "new!";
}
And the test.
void test_ref_to_map() {
MAP valueMap;
valueMap["key"] = "value";
// pass it by reference
function(valueMap);
// check that the value has changed
assert( "new!" == valueMap["key"] );
}
I think this is nice and simple. Enjoy ...
Although it's kinda late but I am still gonna answer, thanks to previous answers on this question i was able to forge this class which reuse pointers and values, it creates two maps to store data, Here the code if anybody interested..
template<class T1, class T2> class Bimap
{
std::map<T1, T2*> map1;
std::map<T2, T1*> map2;
public:
void addRow(T1 &t1, T2 &t2){
map1.insert(make_pair(t1, &t2));
map2.insert(make_pair(t2, &t1));
}
T2* findForward(T1 t1){
T2* value = map1.find(t1)->second;
return value;
}
T1* findBackward(T2 t2){
T1* value = map2.find(t2)->first;
return value;
}
};
Using class:
//Init mapp with int,int
Bimap<int,int> mapp;
//Add a row(Record) in bimap
int a = 5;
int b = 7002;
mapp.addRow(a, b);
//Print a record
int *ans= mapp.findForward(a);
cout<<"Bimap Returned:"<<*ans<<endl;
Related
I want to implement my own "simple" container which will have map properties but also keeps insertion order. I've heard about boost::multi_index but I find it very difficult to understand for what I want.
So I made a templated class:
template<typename KEY, typename VALUE>
class MyMap {
private :
std::vector<KEY> m_keys;
std::vector<VALUE> m_values;
public :
void insert(KEY& key, VALUE& val) {
//Test if key exists //
m_keys.push_back(key);
m_values.push_back(val);
}
/* Other methods like erase/size/operator[]/begin/etc. */
};
Just to test it, I wanted to do something like this:
int main() {
MyMap<string,int> m;
m.insert("test",1);
m.insert("cat",2);
for(auto& item : m) {
cout << item << endl;
cout << m[item] << endl;
}
}
But I keep getting a compilation error on inserts (and [ ]) as it translates my KEY into a basic_string and not a string. It's driving me crazy and I can't find any answer (or any word to properly describe my problem to research for an answer). I guess it has something to do with allocators but I can't manage to understand how to fix it.
How can I make my map do this conversion but also stays general as I will need it with other (own-implemented) classes?
EDIT : After solving "string" problem, I had problems when passing int because it was waiting for an &int. Followed kebs advice and implemented a vector> instead and got rid of conversion problems... :)
You can't build a reference from a const char* (even though it gets casted to a string), try this instead:
template<typename KEY, typename VALUE>
void insert(KEY key, VALUE val) {
m_keys.push_back(key);
m_values.push_back(val);
}
More precisely, the compiler is pretty clear about the problem:
error: invalid initialization of non-const reference of type 'std::basic_string&' from an rvalue of type 'std::basic_string'
m.insert("test",1);
I'm having a problem getting the desired behaviour with array subscription and assignment.
Is there any way to determine whether assignment is used with array subscription?
EDIT
My question probably should have been, can I map [] to a getter, and []= to a setter
// Expect this to return a reference to the value if the key exists,
// or throw an exception if not
myMap["Key"];
// Expect this to always return a reference to the value
// so the value can be populated
myMap["Key"] = "Value";
// The method being used
template <typename K, typename V>
V& MyMap<K, V>::operator[](const K &key)
{
if(this->keyExists(key))
{
return this->find(key);
}
else
{
// At this point I'd like to throw an exception if
// assignment is not being used
this->insert(key, NULL);
return this->pairs[this->itemsStored].val;
}
};
Is there any way to determine whether assignment is used with array
subscription?
Simply, no.
When you do:
myMap["Key"] = "Value";
You're calling two member functions: first, map::operator[] and then -- on a totally different class -- key::operator=. When you simply do myMap["Key"] without the assignment nothing has changed with regards to how you interface with the map. The only difference is what you do next.
You could, I suppose, find some technical hack (like providing a const and non-const version that do different things) which will provide the behavior you are trying to achieve -- but it will be at the cost of poor design. Since you have perscribed within the non-const version that a missing key will be added, subsequently throwing in the non-const version is a major difference. This will be a nightmare to maintain. You will have very strange bugs arise when one version is actually being called when you expected the other to be called. People using your code will be confused and curse your name. Don't do it.
Instead, I suggest you're barking up the entirely wrong tree to begin with. Instead of trying to use operator[] const to determine the existence of a key, why not simply provide a member function that does simply that?
You can, if you wish, have this function throw if the key doesn't exist or simply return a bool.
There's only one way to be sure that no operator= will be called after operator[] (by overloading an operator[] const function), but that wouldn't work every time.
As there's no (easy) way to be able to know when an operator[] is being called with the operator= right after, I'd suggest you to follow the example of std::map by providing two different functions:
operator[], which always return a reference to the object; if the object does not exists, it is created
at, which returns a reference only if the object is already there, otherwise it throws an exception of type std::out_of_range
Yes. Just have the operator[] return a proxy. Something like
the following should work. (I'm using std::map for the
implementation; you can map it to whatever you're using)
template <typename KeyType, typename MappedType>
class MyMap
{
std::map<KeyType, MappedType> myImpl;
// ...
public:
void set( KeyType const& key, MappedType const& value )
{
myImpl[key] = value;
}
MappedType get( KeyType const& key )
{
auto entry = myImpl.find( key );
if ( entry == myImpl.end() ) {
throw DesiredException();
}
return entry->second;
}
class Proxy
{
MyMap* myOwner;
Key myKey;
publc:
Proxy( MyMap& owner, Key const& key )
: myOwner( &owner )
, myKey( key )
{
}
Proxy const& operator=( MappedType const& value ) const
{
myOwner->set( myKey, value );
return *this;
}
operator MappedType() const
{
return myOwner->get( myKey );
}
};
Proxy operator[]( KeyType const& key )
{
return Proxy( *this, key );
}
MappedType operator[]( KeyType const& key ) const
{
return get( key );
}
};
I'm not sure that this is a good idea, however. In general,
having a get( KeyType ) which returns a pointer to the mapped
element, or a null pointer if it isn't present, seems more
natural in C++.
DISCLAIMER : what follows is bad practice, and I do not recommend actually using this. It's merely here to show that what the OP wants is technically possible, even though it's a really bad idea (for reasons I'll go into further).
The bad idea
If you don't mind a bit of hassle, you can have a const and a non-const version of operator[] that behave differently. The const version would throw an exception when accessing a non-existent item, while the non-const version would default-construct a new item in that case.
As a proof of concept :
#include <iostream>
#include <stdexcept>
class Map {
public :
int value;
Map() { value = 42; }
const int& operator[](const size_t& pos) const { if (pos == 0) return value; else throw std::runtime_error("oops"); }
int& operator[](const size_t& pos) { return value; }
};
void showValue(const Map& myMap, size_t pos) {
try {
std::cout << "myMap[" << pos << "] = " << myMap[pos] << std::endl;
}
catch (std::runtime_error e) {
std::cout << "exception when accessing myMap[" << pos << "] : " << e.what() << std::endl;
}
}
int main(void) {
Map myMap;
showValue(myMap, 0);
showValue(myMap, 1);
myMap[0] = 5;
showValue(myMap, 0);
myMap[1] = 10;
showValue(myMap, 0);
return 0;
}
would print :
myMap[0] = 42
exception when accessing myMap[1] : oops
myMap[0] = 5
myMap[0] = 10
But the hassle I mentioned earlier, is to make sure the const version is used whenever the result won't be modified (in the example above, that's done by using a const reference).
Why it's bad
As mentioned at the beginning (and as pointed out by John Dibling in comments), this approach is not recommended. The problem is that :
it's difficult to know which version of operator[] will be called (in those cases where both can be called)
the two versions of operator[] behave differently (one throws an exception while the other would add a new item when called with the same argument)
Combine these two observations, and you get close to unpredictable behaviour, which will hurt you when you least expect it (trust me). And worse, it might be difficult to track down and fix such issues when they occur.
As a rule of thumb, the const and non-const versions of any member function should not differ in their core functionality. Violate that rule, and you invite the wrath of whoever has to maintain the code (and that probably includes your future self).
Any alternatives ?
So, don't do this. Instead, just either do it the same way std::map does (or better yet, just use std::map), or have a contains function you can call to check if an item exists.
I'm getting the following error when trying to build:
error: invalid initialization of non-const reference of type "std::vector<......"
Code:
class Config {
public:
std::vector<string>& GetValuesForList(std::string listName);
private:
std::map<std::string, std::vector<string> > lists;
};
inline std::vector<string>&
Config::GetValuesForList(std::string listName) {
return lists.find(listName);
}
I've read up on it and seems to be because of C++ temporaries, but am unsure how to resolve it. Any help would be greatly appreciated.
Thanks.
map::find returns iterator. So you should use it's second value:
inline std::vector<string>&
Config::GetValuesForList(std::string listName) {
return lists.find(listName)->second;
}
Do you want return lists.find(listName)->second;?
[Side note: lists is not a very good name for a thing that is a map of vector!]
std::map<T>::find() returns a std::map<T>::iterator, not reference to the value type. What you want is the below
inline std::vector<string>&
Config::GetValuesForList(std::string listName) {
std::map<std::string, std::vector<string> >::iterator itr = lists.find(listName);
if (itr != lists.end()) {
return itr->second;;
} else {
// What to do if not found.
}
}
As a note, if you want it to create a new empty vector if not found, then you can simplify the whole thing to
inline std::vector<string>&
Config::GetValuesForList(std::string listName) {
return lists[listName]; // Creates a new vector if listname not found
}
map::find() returns an iterator to pair<key,value>.
I think its better to write this:
std::vector<string>& Config::GetValuesForList(std::string listName)
{
return lists[listName];
}
If the key listName exists in the map, then it will return the associated value. Otherwise, it will create a new entry in the map, and will return the newly created std::vector<T> which would be empty.
I would also like to suggest you to add another function as bool DoesExist(std::string listName) which you may use to inspect, before calling the above function so as to avoid creating new entry if the key is not found:
bool DoesExist(std::string listName)
{
return lists.find(listName) != lists.end();
}
Also, it would be better if you change the name lists to vecMap .
I would like to create C++ class which would allow to return value by given key from map, and key by given value. I would like also to keep my predefined map in class content. Methods for getting value or key would be static. How to predefine map statically to prevent creating map each time I call getValue(str) function?
class Mapping
{
static map<string, string> x;
Mapping::Mapping()
{
x["a"] = "one";
x["b"] = "two";
x["c"] = "three";
}
string getValue(string key)
{
return x[key];
}
string getKey(string value)
{
map<string, string>::const_iterator it;
for (it = x.begin(); it < x.end(); ++it)
if (it->second == value)
return it->first;
return "";
}
};
string other_func(string str)
{
return Mapping.getValue(str); // I don't want to do: new Mapping().getValue(str);
}
Function other_func is called often so I would prefer to use map which is created only once (not each time when other_func is called). Do I have to create instance of Mapping in main() and then use it in other_func (return instance.getValue(str)) or is it possible to define map in class body and use it by static functions?
Is this what you want?
#include <map>
#include <string>
class Mapping
{
private:
// Internally we use a map.
// But typedef the class so it is easy to refer too.
// Also if you change the type you only need to do it in one place.
typedef std::map<std::string, std::string> MyMap;
MyMap x; // The data store.
// The only copy of the map
// I dont see any way of modifying so declare it const (unless you want to modify it)
static const Mapping myMap;
// Make the constructor private.
// This class is going to hold the only copy.
Mapping()
{
x["a"] = "one";
x["b"] = "two";
x["c"] = "three";
}
public:
// Public interface.
// Returns a const reference to the value.
// The interface use static methods (means we dont need an instance)
// Internally we refer to the only instance.
static std::string const& getValue(std::string const& value)
{
// Use find rather than operator[].
// This way you dont go inserting garbage into your data store.
// Also it allows the data store to be const (as operator may modify the data store
// if the value is not found).
MyMap::const_iterator find = myMap.x.find(value);
if (find != myMap.x.end())
{
// If we find it return the value.
return find->second;
}
// What happens when we don;t find anything.
// Your original code created a garbage entry and returned that.
// Could throw an exception or return a temporary reference.
// Maybe -> throw int(1);
return "";
}
};
First of all, you might want to look up Boost::MultiIndex and/or Boost::bimap. Either will probably help a bit with your situation of wanting to use either one of the paired items to look up the other (bimap is more directly what you want, but if you might need to add a third, fourth, etc. key, then MultiIndex may work better). Alternatively, you might want to just use a pair of sorted vectors. For situations like this where the data remains constant after it's been filled in, these will typically allow faster searching and consume less memory.
From there, (even though you don't have to make it explicit) you can handle initialization of the map object itself a bit like a singleton -- put the data in the first time it's needed, and from then on just use it:
class Mapping {
static map<string, string> x;
static bool inited;
public:
Mapping() {
if (!inited) {
x["a"] = "one";
x["b"] = "two";
x["c"] = "three";
inited = true;
}
}
string getValue(string const &key) { return x[key]; }
};
// This initialization is redundant, but being explicit doesn't hurt.
bool Mapping::inited = false;
map<string, string> Mapping::x;
With this your some_func could look something like this:
string some_func(string const &input) {
return Mapping().getValue(input);
}
This still has a little overhead compared to pre-creating and using an object, but it should be a lot less than re-creating and re-initializing the map (or whatever) every time.
If you are looking up the value from the key a lot, you will find it easier and more efficient to maintain a second map in parallel with the first.
You don't need to create a static map especially if you ever want to create multiple Mapping objects. You can create the object in main() where you need it, and pass it around by reference, as in:
string other_func(Mapping &mymap, string str)
{
return mymap.getValue(str);
}
Of course this raises questions about efficiency, with lots of strings being copied, so you might want to just call getValue directly without the extra overhead of calling other_func.
Also, if you know anything about the Boost libraries, then you might want to read up on Boost.Bimap which is sort of what you are implementing here.
http://www.boost.org/doc/libs/1_42_0/libs/bimap/doc/html/index.html
Static is bad. Don't. Also, throw or return NULL pointer on not found, not return empty string. Other_func should be a member method on the object of Mapping, not a static method. This whole thing desperately needs to be an object.
template<typename Key, typename Value> class Mapping {
std::map<Key, Value> primmap;
std::map<Value, Key> secmap;
public:
template<typename Functor> Mapping(Functor f) {
f(primmap);
struct helper {
std::map<Value, Key>* secmapptr;
void operator()(std::pair<Key, Value>& ref) {
(*secmapptr)[ref.second] = ref.first;
}
};
helper helpme;
helpme.secmapptr = &secmap;
std::for_each(primmap.begin(), primmap.end(), helpme);
}
Key& GetKeyFromValue(const Value& v) {
std::map<Value,Key>::iterator key = secmap.find(v);
if (key == secmap.end())
throw std::runtime_error("Value not found!");
return key->second;
}
Value& GetValueFromKey(const Key& k) {
std::map<Key, Value>::iterator key = primmap.find(v);
if (key == primmap.end())
throw std::runtime_error("Key not found!");
return key->second;
}
// Add const appropriately.
};
This code uses a function object to initialize the map, reverses it for you, then provides accessing methods for the contents. As for why you would use such a thing as opposed to a raw pair of std::maps, I don't know.
Looking at some of the code you've written, I'm guessing that you originate from Java. Java has a lot of things that C++ users don't use (unless they don't know the language) like singletons, statics, and such.
I have the following issue 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 table with pairs of string keys associated to string data. Somewhere else I have a method toString that returns a string object that contains all the keys and 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'm trying to compile I get the following error:
error: "error: no match for call to ‘(std::basic_string<char,
std::char_traits<char>, std::allocator<char> >) ()’".
Could somebody explain to me what is missing, what I'm doing wrong?
I only found some discussion about a similar issue in the case of hash_map where the user has to define a hashing function to be able to use hash_map with std::string objects. Could be something similar also in my case?
Your main problem is that you are calling a method called first() in the iterator. What you are meant to do is use the property called first:
...append(iter->first) rather than ...append(iter->first())
As a matter of style, you shouldn't be using new to create that string.
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 pointed out (in the comments) that in modern C++ you can now rewrite the loop
for (auto& item: table) {
...
}
Don't write a toString() method. This is not Java. Implement the stream operator for your class.
Prefer using the standard algorithms over writing 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 don't intend to change the data, prefer const_iterator over iterator. That way, if you accidently try and 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 stream the object:
int main()
{
something bob;
std::cout << bob;
}
If you actually need a string representation of the object, you can then use lexical_cast.
int main()
{
something bob;
std::string rope = boost::lexical_cast<std::string>(bob);
}
The details that need to be filled in.
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 << data.first << "=" << data.second << "\n";
}
private: std::ostream& m_str;
};
DataMap table;
public:
void something::print(std::ostream& str);
};
Change your append calls to say
...append(iter->first)
and
... append(iter->second)
Additionally, the line
std::string* strToReturn = new std::string("");
allocates a string 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 don't want to worry about managing that object on the heap, change the local declaration to
std::string strToReturn("");
and change the 'append' calls to use reference syntax...
strToReturn.append(...)
instead of
strToReturn->append(...)
Be aware that this will construct the string on the stack, then copy it into the return variable. This has performance implications.
Note that the result of dereferencing an std::map::iterator is an std::pair. The values of first and second are not functions, they are variables.
Change:
iter->first()
to
iter->first
Ditto with iter->second.
iter->first and iter->second are variables, you are attempting to call them as methods.
Use:
std::map<std::string, std::string>::const_iterator
instead:
std::map<std::string, std::string>::iterator
Another worthy optimization is the c_str ( ) member of the STL string classes, which returns an immutable null terminated string that can be passed around as a LPCTSTR, e. g., to a custom function that expects a LPCTSTR. Although I haven't traced through the destructor to confirm it, I suspect that the string class looks after the memory in which it creates the copy.
In c++11 you can use:
for ( auto iter : table ) {
key=iter->first;
value=iter->second;
}