avoid temporary std::string to invoke boost::unordered_map::find

ε祈祈猫儿з 提交于 2019-12-11 07:32:11

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!