Reputation: 469
I'm using a std::unordered_map
with keys of Currency
and values with a double
of the currency price. Currency
is a custom class that I made. Here is one version that I have tried:
#ifndef CURRENCY_H
#define CURRENCY_H
#include "Nameable.h"
#include <boost/uuid/uuid.hpp>
#include <boost/uuid/uuid_generators.hpp>
#include <boost/uuid/uuid_io.hpp>
#include <boost/functional/hash.hpp>
#include "BigDecimal.h"
#include <iostream>
/**
* Represents a single currency. Can be used as keys in a map and as a general
* identifier for determining what unit a value of money is.
* @param name
*/
class Currency: public Nameable {
public:
Currency(std::string name) throw(NameAlreadyTakenException);
Currency(const Currency& orig);
virtual ~Currency();
virtual std::string getName();
virtual void setName(std::string name) throw(NameAlreadyTakenException);
inline bool operator==(const Currency& key) const {
return this->id == key.id;
}
// A custom hasher that I tried using.
struct currencyHasher
{
std::size_t operator()(const Currency& k) const
{
return boost::hash<boost::uuids::uuid>()(k.id);
}
};
boost::uuids::uuid id;
private:
};
// A template specialization for Currency.
namespace std {
template <>
struct hash<Currency> {
std::size_t operator()(const Currency& k) const {
cout<< boost::hash<boost::uuids::uuid>()(k.id)<<"\n";
return boost::hash<boost::uuids::uuid>()(k.id);
}
};
}
#endif /* CURRENCY_H */
And here is the implementation:
#include "Currency.h"
Currency::Currency(std::string name) throw(NameAlreadyTakenException) {
this->setName(name);
this->id = boost::uuids::random_generator()();
}
Currency::Currency(const Currency& orig) {
}
Currency::~Currency() {
}
std::string Currency::getName() {
return this->name;
}
void Currency::setName(std::string name) throw(NameAlreadyTakenException) {
this->name = name;
}
I tried making Currency
key-compatible by implementing both suggestions given by the answer to: C++ unordered_map using a custom class type as the key. As you can see I've overridden the operator== as well as providing a custom hasher as well as specialize the template.
Despite all of this, the keys seem to be losing the values. By this I mean doubles, floats and ints get turned into 0 and string get turned into empty strings. Of course, it causes other problems with anything else that I use as a value. For example:
Currency dollar("Dollar")
std::unordered_map<Currency,int,Currency::currencyHasher> currenMap;
currenMap[dollar]=1337;
std::cout<<currenMap[dollar]<<"\n";
The output of this in the console is 0. Utilizing the template specialization doesn't work either:
std::unordered_map<Currency,int> currenMap;
currenMap[dollar]=1337;
std::cout<<currenMap[dollar]<<"\n";
produces a 0 as well...
Could the fact that Currency
is a subclass of Nameable
be causing problems? I'm using the boost::uuid as the hash (utilizing boost::hash<boost::uuids::uuid>
to convert the id into a size_t
) I'm not sure what I'm missing, I thank you for your help.
Upvotes: 1
Views: 2025
Reputation: 302842
The issue is with the copy constructor:
Currency::Currency(const Currency& orig) {
}
When you copy a Currency
, you get a default-constructed id
. When you insert a Currency
into the map, it gets copied, and that copy will have a different id than the original. Thus this:
currenMap[dollar]=1337;
is effectively adding {Currency(), 1337}
into the map. So when you are looking up the one with whatever id gets created for dollar
, it won't be there. It's not that the value gets "zeroed out"... it's that you get a default-constructed value back.
Fixing your copy constructor should fix the problem.
Upvotes: 2