"Invalid initialization" error when reading from a map - c++

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 .

Related

How to handle a function that is not guaranteed to return anything?

I have a class that stores & manages a vector containing a number of objects.
I'm finding myself writing a number of functions similar to the following:
Object* ObjectManager::getObject(std::string name){
for(auto it = object_store.begin(); it != object_store.end(); ++it){
if(it->isCalled(name))
return &(*it)
}
return nullptr;
}
I think I would rather return by reference, as here the caller would have to remember to check for null! Is there a way I can change my design to better handle this?
Your alternatives are outlined below
Change your API to the following
object_manager.execute_if_has_object("something", [](auto& object) {
use_object(object);
});
This API is much easier to use, conveys intent perfectly and removes the thought process of error handling, return types, etc from the user's mind
Throw an exception.
Object& ObjectManager::getObject(const std::string& name){
for(auto& object : object_store){
if(object.isCalled(name))
return object;
}
// throw an exception
throw std::runtime_error{"Object not found"};
}
Return a bool, pass the Object by reference and get a copy
bool ObjectManager::getObject(const std::string& name, Object& object_out){
for(auto& object : object_store){
if(object.isCalled(name)) {
object_out = object;
return true;
}
}
return false;
}
Let the user do the finding
auto iter = std::find(object_store.begin(), object_store.end(), [&name](auto& element) {
return element.isCalled(name);
}
if (iter != object_store.end()) { ... }
Also
Pass that string by const reference. When C++17 is available change that const reference to a std::string_view
Use range based for loops in this situation, they are a more readable alternative for what you are doing
Look at the design of STL (e.g. find function), it is not at all bad to return the iterator your just searched for, and return .end() otherwise.
auto ObjectManager::getObject(std::string name){
for(auto it = object_store.begin(); it != object_store.end(); ++it){
if(it->isCalled(name))
return it;
}
return object_store.end();
}
More: Of course object_store.end() may be inaccessible from outside the class but that is not an excuse, because you can do this (note the more slick code also)
auto ObjectManager::getObject(std::string name){
auto it = object_store.begin();
while(not it->isCalled(name)) ++it;
return it;
}
auto ObjectManager::nullObject(){return object_store.end();}
Less code is better code. You can use it like this:
auto result = *om.getObject("pizza"); // search, not check (if you know what you are doing)
or
auto it = om.getObject("pizza");
if(it != om.nullObject() ){ ... do something with *it... }
or
auto it = om.getObject("pizza");
if(it != om.nullObject() ){ ... do something with *it... }
else throw java_like_ridiculous_error("I can't find the object, the universe will collapse and it will jump to another plane of existence");
Of course at this point it is better to call the functions findOject and noposObject and also question why not using directly std::find on the object_store container.
I think you are already handling the return value properly and your current solution is optimal.
The fact is you can not avoid checking for something in order to discover if your find operation succeeded. If you throw an exception then your try{}catch{} is your check. Also an exception should not be used when not finding an item is a legitimate result. If you return a bool and use an out parameter you have made the situation more complicated to do the same job. Same with returning an iterator. A std::optional returns values.
So IMO you can't improve upon returning a pointer you can just make the same job more complicated.
Solution alternative to exceptions or optional is to implement a "Null object" - which can be used as a regular object, but will "do nothing". Depends on the case, sometimes it can be used as is and does not require to be checked (explicitly) - especially in cases where ignoring the "not found" situation is acceptable.
(the null object can be a static global, so it is also possible to return a reference to it)
Even if a check is needed, an isNull() method can be implemented, which returns true for the null object and false for a valid object (or there can be isValid() method, etc.).
Example:
class Object {
public:
virtual void doSomething();
};
class NullObject: public Object {
public:
virtual void doSomething() {
// doing nothing - ignoring the null object
}
};
class ObjectManager {
public:
Object& getObject(const std::string& name);
private:
static NullObject s_nullObject;
};
Object& ObjectManager::getObject(const std::string& name){
for(auto it = object_store.begin(); it != object_store.end(); ++it){
if(it->isCalled(name))
return *it;
}
return s_nullObject;
}
ObjectManager mgr;
Object& obj = mgr.getObject(name);
obj.doSomething(); // does nothing if the object is NullObject
// (without having to check!)

protobuf: RepeatedField unique elements

I want to have in a google protocol buffer repeated field only unique elements. In other words, need to use it as a std::set instead of std::vector.
Any idea which is the simplest and most efficient way to do that?
EDIT: I wouldn't want to use any iterators to loop through all the elements if possible.
Ok, as the comments from the question stated, there isn't any way of doing this without using iterators.
However, maybe someone else is interested in this, here is the function i coded to achieve this. This will take as parameters a RepeatedPtrField< T >*(the list) and a std::string(key of the new object that we intend to add to the list) and will return the element that matches the id, or NULL if there isn't any entry with this key in the RepeatedField list.
This way, you can easy keep a list of unique elements directly in a RepeatedField without using any other std structure:
template <class T>
T* repeatedFieldLookup( google::protobuf::RepeatedPtrField< T >* repeatedPtrField, std::string id)
{
google::protobuf::internal::RepeatedPtrOverPtrsIterator<T> it = repeatedPtrField->pointer_begin();
for ( ; it != repeatedPtrField->pointer_end() ; ++it )
{
CommonFields * commonMessage = (CommonFields*) (*it)->GetReflection()->
MutableMessage ((*it), (*it)->GetDescriptor()->FindFieldByName ("common"));
if(commonMessage->id() == id)
{
return *it;
}
}
return NULL;
}
NOTE: in the example above, the proto message will ALWAYS have a field called common(which in my case is also a proto message). You can replace that by anything that you want to make the comparison from your proto messages.
In the case where I had this class:
class Description : public ::google::protobuf::Message {
// ...
inline void add_field(const ::std::string& value);
inline const ::google::protobuf::RepeatedPtrField< ::std::string>& field() const;
// ...
};
I used std::find to only add a value if it didn't exist in the list:
#include <algorithm>
void addField(Description& description, const std::string& value) {
const auto& fields = description.field();
if (std::find(fields.begin(), fields.end(), value) == fields.end()) {
description.add_field(value);
}
}

How can I get a value from a map?

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;

Access to map data

I have a complex map that defined
typedef short short1
typedef short short2
typedef map<short1,short2> data_list;
typedef map<string,data_list> table_list;
I have a class that fill table_list
class GroupingClass
{
table_list m_table_list;
string Buildkey(OD e1){
string ostring;
ostring+=string(e1.m_Date,sizeof(Date));
ostring+=string(e1.m_CT,sizeof(CT));
ostring+=string(e1.m_PT,sizeof(PT));
return ostring;
}
void operator() (const map<short1,short2>::value_type& myPair) {
OD e1=myPair.second;
string key=Buildkey(e1);
m_table_list[key][e1.m_short1]=e1.m_short2;
}
operator table_list() {
return m_table_list;
}
};
and I use it by
table_list TL2
GroupingClass gc;
TL2=for_each(mapOD.begin(), mapOD.end(), gc);
but when I try to access to internal map I have problems
for example
data_list tmp;
tmp=TL2["AAAA"];
short i=tmp[1]; //I dont update i variable
and when debug it, I see code try add new value to map.then when tmp var is const this cause to a error
but if i use a loop by itrator this work properly
why this no work at first way
thanks herzl
std::map<Key,Value>::operator[](Key const& k) will look for key k. If it's not found, it will insert a new Value() and return a reference to that. This is a modifying operation. Therefore, operator[] is non-const.
The code does not make sense. What is OD? myPair.second would be short in operator() but then you do e1.m_short2 which does not make any sense.
Your likely bug is that for_each takes its 3rd parameter by value which means it is going to make copies of that map and probably you will lose the changes.
You can force for_each to take the 3rd value by reference either by specifying the template parameter directly or by wrapping in boost::ref. However you would do far better to make your functor take the map it is building by reference in its constructor rather than have an instance of a map.
class GroupingClass
{
table_list & m_table_list;
string Buildkey(OD e1)
{
string ostring;
ostring+=string(e1.m_Date,sizeof(Date));
ostring+=string(e1.m_CT,sizeof(CT));
ostring+=string(e1.m_PT,sizeof(PT));
return ostring;
}
public:
explicit GroupingClass( table_list & the_table_list ) :
m_table_list( the_table_list )
{
}
void operator() (const map<short1,short2>::value_type& myPair) const
{
OD e1(myPair.first); // probably what you meant
string key=Buildkey(e1);
m_table_list[key][e1.m_short1]=e1.m_short2;
// did you mean m_table_list[key][myPair.first] = myPair.second; ?
}
};
and use it by
table_list TL2;
for_each(mapOD.begin(), mapOD.end(), GroupingClass(TL2));

How to iterate over a std::map full of strings in C++

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;
}