问题
I have the following type:
boost::unordered_map< std::string , Domain::SomeObject > objectContainer;
which is just a map to some domain object, using std::strings
as keys. Now, std::string
can be constructed and compared with const char*
. (no need for an explicit std::string
temporary, although maybe a implicit conversion is happening?)
The problem happens when I try to do something like
void findStuff(const char* key) {
auto it = objectContainer.find(key); //<---build error
}
My main concern here is that it seems a little bit overkill to build a std::string
just to make a comparison against an inmutable std::string
, because the std::string
temporary will want to have its own buffer, copy the const char*
content in it, and then use that to run the find()
method.
Is there a shortcut I can use to avoid the creation of a std::string
temporary in here?
回答1:
Of course. Redeclare your function like this:
void findStuff(std::string const & key);
Now use std::string
in the calling code right from the start.
回答2:
You could run through all the keys one by one, and compare them with old strcmp if you really did not want to create any extra std::string. But Kerrek solution is the best in my opinion
回答3:
You could inherit the boost::unordered_map and add a find with a version for "char *" that handles the temp std::string for you.
//boost::unordered_map< std::string , Domain::SomeObject > objectContainer;
class ObjectContainer::public boost::unordered_map< std::string , Domain::SomeObject >
{
public:
iterator find(const char *key){const std::string constKey(key); return boost::unordered_map< std::string , Domain::SomeObject >::find(constKey);}
const_iterator find(const char *key)const {const std::string constKey(key); return boost::unordered_map< std::string , Domain::SomeObject >::find(constKey);}
};
ObjectContainer objectContainer;
Also take the above with a grain of salt as I have not tested that. My current setup VS2008 with boost 1.40 does not have an issue with feeding a const char * to find (I am also not using auto). It does have an issue with const char * and the operator[] function to which I have done something similar for the operator[] function allowing access like objectContainer["key"]
回答4:
Main problem is declare of your container.
boost::unordered_map< std::string , Domain::SomeObject > objectContainer;
If look to source we will see :
template<typename Key, typename Mapped, ...>
class unordered_map;
iterator find(const Key &);
So, you have strong restrictions by interface. Method find always use Key type as parameter and you can't change it without changing container key type.
If you sure that lose too many time on initialization of std::string you can use buffer (if no threads). For example :
class objectContainer : public boost::unordered_map<std::string, SomeObject>
{
std::string _buffer;
public:
typedef boost::unordered_map<std::string, SomeObject> inherited;
objectContainer() { _buffer.reserve(1024); }
typename inherited::iterator find(const char * key)
{
_buffer = key;
return inherited::find(_buffer);
}
};
Now, buffer allocates memory only once in constructor, not every time when call find.
Other way, use your own key type which can work std::string and const char *, but at this case you should to define implementation of Hash(boost::hash<Key>
), predicate ( std::equal_to<Key>
) with your Key type.
Something like this :
class Key
{
public:
virtual ~Key();
virtual const char * key() = 0; // for hash and predicate
};
// predicate
struct equal_to_Key : binary_function <Key,Key,bool> {
bool operator() (const Key & x, const Key & y) const
{
return false; // TODO : compare Key here
}
};
class CharKey : public Key
{
const char * _key;
public:
virtual const char * key() { return _key; }
};
class StringKey : public Key
{
std::string _key;
public:
virtual const char * key() { return _key.c_str(); }
};
Now, you have one way to get const char * and use it in hash and predicate. When you insert string you prefer to use StringKey. When find - CharKey.
boost::unordered_map< Key , Domain::SomeObject, KeyHashFunctor, equal_to_Key > objectContainer;
void findStuff(const char* key) {
auto it = objectContainer.find(CharKey(key));
}
But, at this case added virtual functions and creating Key objects might reduce perfomance and working with objectContainer became non-comfortable.
回答5:
//<---build error
What error? It should compile as-is. Unfortunately there's no simple way to do what you'd like. I've been bitten by the same issue. :(
There are multiple problems: parameter type of find()
, types of std::equal_to
, std::hash
and std::less
回答6:
Try using this :-
void findStuff(const char* key)
{
std::string abc = (std::string)key; //<---build error
auto it = objectContainer.find(abc); // Now use "abc to find in Map
}
来源:https://stackoverflow.com/questions/9444076/avoid-temporary-stdstring-to-invoke-boostunordered-mapfind