using unordered map find function - c++

If I want the unordered map find function to return a bool value, how would I go about doing that?
Here's my code right now.
bool NS_SymbolTable::SymbolTable::Contains(std::string lexeme)
{
SymbolTable *tempSymbolTable = this;
std::unordered_map<std::string, Identifier*>::iterator it = tempSymbolTable->hashtable.find(lexeme);
return std::boolalpha;
}
What else do I neeed to do ? Is it possible to return a bool? There is little to no documentation on this that I have found.
This is where I got an example from http://msdn.microsoft.com/en-us/library/bb982431.aspx

tempSymbolTable->hashtable.find(lexeme) will return tempSymbolTable->hashtable.end() if it fails, so you can convert this result to a bool very simply:
return tempSymbolTable->hashtable.find(lexeme) != tempSymbolTable->hashtable.end();
Also, assigning this to a temporary variable and working through that is unnecessary. Your function can be reduced to:
bool NS_SymbolTable::SymbolTable::Contains(std::string lexeme)
{
return hashtable.find(lexeme) != hashtable.end();
}

For documentation look std::unordered_map::find. There it says:
Return value
iterator to an elements with key key. If no such element is found, past-the-end (see end()) iterator is returned.
To get boolean value indicating whether an element is present, use
bool contained = it != tempSymbolTable->hashtable.end();

bool NS_SymbolTable::SymbolTable::Contains(std::string lexeme)
{
SymbolTable *tempSymbolTable = this;
return tempSymbolTable->hashtable.end() != tempSymbolTable->hashtable.find(lexeme);
}

You need to test the return value of find against tempSymbolTable->hastable.end(), if they are equal then it did not find your element. The reason find works like this is because in its current form it is more general than something that returns only a bool.

std::unordered_map::find(), like the rest of the standard containers' find functions, returns end() on failure.
Try this:
bool NS_SymbolTable::SymbolTable::Contains(std::string lexeme)
{
SymbolTable *tempSymbolTable = this;
std::unordered_map<std::string, Identifier*>::iterator it =
tempSymbolTable->hashtable.find(lexeme);
return it != tempSymbolTable->hashtable.end();
}
Reference:
MSDN unordered_map::find
MSDN unordered_map::equal_range
EDIT: change sense of return value.

Related

How to properly handle if a function exits without encoutering a return

I have a function that search a vector and returns the item if it is found. But I want to know that best software appraoch to handle if it is not found.
I have created a function and could return -1 or something but that wouldn't match the return type.
koalaGraph::PVertex Koala::lookUpVertexbyName(const std::string&vertexName, const std::vector<koalaGraph::PVertex>& koalaVertices) {
for (size_t i = 0; i < koalaVertices.size(); i++) {
if(koalaVertices[i]->info.name == vertexName)
return koalaVertices[i];
}
}
If a situation is encountered where the item being searched for is not in the vector then program will exit.
You can use std::optional
#include <optional>
std::optional<koalaGraph::PVertex>
Koala::lookUpVertexbyName(const std::string&vertexName,
const std::vector<koalaGraph::PVertex>& koalaVertices) {
for (size_t i = 0; i < koalaVertices.size(); i++) {
if(koalaVertices[i]->info.name == vertexName)
return koalaVertices[i];
}
return {};
}
int main()
{
Koala k;
//...
auto maybeVertex = k.lookUpVertexByName("foo",vertices);
if(maybeVertex)
koalaGraph::PVertex&& vertex = *maybeVertex;
//alternatively
if(maybeVertex.has_value())
//found
}
You could use a for-loop and return a iterator.
std::vector<koalaGraph::PVertex>::const_iterator
Koala::lookUpVertexbyName(
const std::string&vertexName,
const std::vector<koalaGraph::PVertex>& koalaVertices)
{
for(auto iter = koalaVertices.begin(); iter != koalaVertices.end(); ++iter) {
if(koalaVertices[i]->info.name == vertexName) {
return iter;
}
}
return koalaVertices.end();
}
Further you check if you got end back. end indicates if the value was found or not.
auto iter = <fucntioncall> // lookUpVertexbyName
if (iter == <vector>.end() {
// abort or do what ever you want
}
To use the value you have to dereference the iterator. DON'T derefence the end-iterator, it will lead you to neverland -> undefined behavior.
std::string test = *iter;
Why not use std::find_if instead of reinventing the wheel. See this link.
struct equal
{
equal(const std::string& vertexName) : vertexName_(vertexName) { }
bool operator()(const koalaGraph::PVertex& pVertex) const
{
return pVertex->info.name == vertexName_;
}
private:
std::string vertexName_;
};
And then:
std::find_if(koalaVertices.begin(), koalaVertices.end(), eq(vertexName));
Regarding handling the errors in function as it has already been stated there are multiple approaches that one can take. Returning an iterator instead of object(you will avoid copying this way too) is one of them. end() iterator would then indicate that the name was not found.
There are three ways to exit a function:
Return a value
Throw a value
Call std::abort or std::exit (possibly indirectly)
(std::longjmp which you shouldn't use)
If you don't do any of the above, then behaviour will be undefined. If you don't want to do 1., then your options are 2. or 3. Abort and exit will terminate the process. A throw can be caught, but an uncaught throw will cause std::abort.
Note that just because you don't find a value, it's not necessarily impossible to return some value. What you can do is return a "sentinel" value that represents "not found". For example, std::string functions that return an index will return std::string::npos when there is no result. Functions returning a pointer might return null, and functions returning an iterator would return an iterator the the end of the range.
If there is no representation of your return type that could be reserved for a sentinel, there is a way to add such representation by wrapping the return type with additional state. The standard library has a generic wrapper for this: std::optional.
Another wrapper is the proposed std::expected (it's not accepted to the standard as far as I know, but there are plenty of non-standard implementations). It allows storing information about the reason for not returning a proper value which similar to what you can do with exceptions.
P.S. Your function appears to be nearly identical to std::find_if. Use standard algorithms when possible. Also consider a data structure that is more efficient for searching if the search space is large.

What would I return in this situation

I will post my code then explain my query:
typedef std::shared_ptr<SEntity> Entity;
//Scene_Ids is an enum
static std::map<Scene_Ids, std::vector<Entity> > m_scene_entities;
std::shared_ptr<SEntity>& SEntityManager::getEntity(const std::string& entity_name)
{
int counter = 0;
for (auto iter = m_scene_entities.begin(); iter != m_scene_entities.end(); ++iter)
{
if (iter->second[counter]->getId() == entity_name)
return iter->second[counter];
counter++;
}
//What would I return if the entity couldn't be found?
}
The code basically explains it all. I have a method in which if an "entity" is found in the std::vector inside of the map, it will return a reference to the std::shared_ptr type that it is. However, since I'm not returning a pointer, I cannot return nullptr. What could I return in a failure case.
Also, I know that std::shared_ptr is meant for having copies in several different places. For this, do I really need to return a reference or can I just return it by value?
Thanks!
Return the iterator rather than the contents of the iterator. That way you can tell whether you reached the end.
If it is expected that under normal circumstances getEntity will never fail to find the entity, then you should throw an exception.
If you would expect to fail to find some entites, then you can return a default-constructed shared_ptr <SEntity>. Be sure to check for that on the other end.
Remove the return by reference then return an empty shared pointer:
std::shared_ptr<SEntity> SEntityManager::getEntity(const std::string& entity_name) {
for { ... }
return Entity();
}
There's not really a good reason to return the shared pointer by reference. And the shared pointer has a default constructor that's basically the equivalent of nullptr. You can check it in the parent function by testing it as a bool. E.g.:
auto val = getEntity(...);
if (!val) { /* nothing found */ }
I suspect that you need to split tasks. For any normal operation (changing the values of SEntity parameters) you will just need to either return default constructed std::shared_ptr or found entity. No reference needed.
For *replacing the actual contents of shared_ptr* you can have a function like
void SEntityManager::replaceEntity(const std::string& entity_name, Entity* newEntity)
and replace the Entity if its found inside the function.
However, your code still is weird - what if, for example, there are multiple entity_name containing Entities in your vectors ?

How to return from a non-void function?

I have a function below that searches through a vector of my_type. Currently, it has a compilation warning: control reaches end of non-void function [-Wreturn-type]. It appears that as long as I am using a reference as my return type rather than a pointer, it is not possible to return a null-like value?
struct my_type{
type_a a;
type_b b;
}
type_b& value(type_a& t){
typename std::vector<my_type>::iterator it;
for(it = v.begin(); it != v.end(); ++it){
if ((*it).a == t) return (*it).b;
}
}
It appears that as long as I am using a reference as my return type rather than a pointer, it is not possible to return a null-like value?
Well, yes, but that's not the only issue. References can never be null, but what happens if your if statement never evaluates to true? You don't return anything.
Since references cannot be null, it is not valid to return null. You must return a valid reference from all execution paths.
Also, your code is fragile at best. You are returning a reference to a member of an element in a container... an element that may be moved at any point in the future, making said reference invalid.
The question you have to think about is what should you return if 'nothing' is found when your function has to return my_type. How you handle this directly affects how the caller uses this function and assumptions made.
There are a few ideas you can think about. For example, if your value function returned a pointer type, you could just return NULL to indicate nothing. If it returned a string, you can use an empty string "" or even a special string value like "none" to indicate that. For type_b you can create a special instance of it and just return that instance to indicate nothing. Other functions calling this would check the returned type_b against that instance to see if it's nothing. The point is, there are many ways to go about it and which way you choose is up to you.
But a better approach would be to use what's already provided by the stl -- in particular std::find_if. For example, you can create a functor which specifies when there's a match:
struct find_b
{
const type_a &this_a;
find_b(const type_a &a) : this_a(a) {}
bool operator() (const my_type &lhs)
{
return lhs.a == this_a;
}
};
Then you would use it like this:
item = std::find_if(v.begin(), v.end(), find_b(t));
if(item == v.end()) { /* not found */ }
else { /* found, do something useful here */ }

"Invalid initialization" error when reading from a map

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 .

Return a "NULL" object if search result not found

I'm pretty new to C++ so I tend to design with a lot of Java-isms while I'm learning. Anyway, in Java, if I had class with a 'search' method that would return an object T from a Collection< T > that matched a specific parameter, I would return that object and if the object was not found in the collection, I would return null. Then in my calling function I would just check if(tResult != null) { ... }
In C++, I'm finding out that I can't return a null value if the object doesn't exist. I just want to return an 'indicator' of type T that notifies the calling function that no object has been found. I don't want to throw an exception because it's not really an exceptional circumstance.
This is what my code looks like right now:
class Node {
Attr& getAttribute(const string& attribute_name) const {
//search collection
//if found at i
return attributes[i];
//if not found
return NULL; // what should this be?
}
private:
vector<Attr> attributes;
}
How can I change it so I can give that kind of marker?
In C++, references can't be null. If you want to optionally return null if nothing is found, you need to return a pointer, not a reference:
Attr *getAttribute(const string& attribute_name) const {
//search collection
//if found at i
return &attributes[i];
//if not found
return nullptr;
}
Otherwise, if you insist on returning by reference, then you should throw an exception if the attribute isn't found.
(By the way, I'm a little worried about your method being const and returning a non-const attribute. For philosophical reasons, I'd suggest returning const Attr *. If you also may want to modify this attribute, you can overload with a non-const method returning a non-const attribute as well.)
There are several possible answers here. You want to return something that might exist. Here are some options, ranging from my least preferred to most preferred:
Return by reference, and signal can-not-find by exception.
Attr& getAttribute(const string& attribute_name) const
{
//search collection
//if found at i
return attributes[i];
//if not found
throw no_such_attribute_error;
}
It's likely that not finding attributes is a normal part of execution, and hence not very exceptional. The handling for this would be noisy. A null value cannot be returned because it's undefined behaviour to have null references.
Return by pointer
Attr* getAttribute(const string& attribute_name) const
{
//search collection
//if found at i
return &attributes[i];
//if not found
return nullptr;
}
It's easy to forget to check whether a result from getAttribute would be a non-NULL pointer, and is an easy source of bugs.
Use Boost.Optional
boost::optional<Attr&> getAttribute(const string& attribute_name) const
{
//search collection
//if found at i
return attributes[i];
//if not found
return boost::optional<Attr&>();
}
A boost::optional signifies exactly what is going on here, and has easy methods for inspecting whether such an attribute was found.
Side note: std::optional was recently voted into C++17, so this will be a "standard" thing in the near future.
You can easily create a static object that represents a NULL return.
class Attr;
extern Attr AttrNull;
class Node {
....
Attr& getAttribute(const string& attribute_name) const {
//search collection
//if found at i
return attributes[i];
//if not found
return AttrNull;
}
bool IsNull(const Attr& test) const {
return &test == &AttrNull;
}
private:
vector<Attr> attributes;
};
And somewhere in a source file:
static Attr AttrNull;
If you want a NULL return value you need to use pointers instead of references.
References can't themselves be NULL.
(Note to the future comment posters: Yes you can have the address of a reference be NULL if you really really try to).
See my answer here for a list of differences between references and pointers.
As you have figured out that you cannot do it the way you have done in Java (or C#). Here is another suggestion, you could pass in the reference of the object as an argument and return bool value. If the result is found in your collection, you could assign it to the reference being passed and return ‘true’, otherwise return ‘false’. Please consider this code.
typedef std::map<string, Operator> OPERATORS_MAP;
bool OperatorList::tryGetOperator(string token, Operator& op)
{
bool val = false;
OPERATORS_MAP::iterator it = m_operators.find(token);
if (it != m_operators.end())
{
op = it->second;
val = true;
}
return val;
}
The function above has to find the Operator against the key 'token', if it finds the one it returns true and assign the value to parameter Operator& op.
The caller code for this routine looks like this
Operator opr;
if (OperatorList::tryGetOperator(strOperator, opr))
{
//Do something here if true is returned.
}
The reason that you can't return NULL here is because you've declared your return type as Attr&. The trailing & makes the return value a "reference", which is basically a guaranteed-not-to-be-null pointer to an existing object. If you want to be able to return null, change Attr& to Attr*.
You are unable to return NULL because the return type of the function is an object reference and not a pointer.
There is one more option that could be considered in this situation - depending on your design. You can return the value using an argument to your function and make the function return bool, e.g.
bool getAttribute(const string& attribute_name, Attr& returnAttr) const {
//search collection
//if found at i
returnAttr = attributes[i];
return true;
//if not found
return false;
}
You can try this:
return &Type();