How can I get a value from a map?

C++DictionaryStdmap

C++ Problem Overview


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?

C++ Solutions


Solution 1 - C++

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.

Solution 2 - C++

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/

Solution 3 - C++

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

Solution 4 - C++

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

Solution 5 - C++

> 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 ...

Solution 6 - C++

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;

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionAneesh NarayananView Question on Stackoverflow
Solution 1 - C++Steve JessopView Answer on Stackoverflow
Solution 2 - C++Gabe RainbowView Answer on Stackoverflow
Solution 3 - C++honkView Answer on Stackoverflow
Solution 4 - C++AitorView Answer on Stackoverflow
Solution 5 - C++Chef GladiatorView Answer on Stackoverflow
Solution 6 - C++Agent_OrangeView Answer on Stackoverflow