避免使用临时std::string来调用boost::unordereded_map::find

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

本文关键字:boost 调用 unordereded find map string std      更新时间:2023-10-16

我有以下类型:

 boost::unordered_map< std::string , Domain::SomeObject > objectContainer;

其只是使用std::strings作为密钥的到某个域对象的映射。现在,可以构造std::string,并将其与const char*进行比较。(不需要显式std::string临时,尽管可能正在发生隐式转换?)

当我尝试做类似的事情时,就会出现问题

void findStuff(const char* key) {
  auto it = objectContainer.find(key); //<---build error
}

我在这里主要担心的是,仅仅为了与不可变的std::string进行比较而构建std::string似乎有点过头了,因为std::string临时需要有自己的缓冲区,复制其中的const char*内容,然后使用它来运行find()方法。

有没有一个快捷方式可以避免在这里创建std::string临时?

当然。像这样重新声明你的函数:

void findStuff(std::string const & key);

现在,从一开始就在调用代码中使用std::string

主要问题是容器的声明。

boost::unordered_map< std::string , Domain::SomeObject > objectContainer;

如果查看来源,我们将看到:

template<typename Key, typename Mapped, ...> 
    class unordered_map;
iterator find(const Key &);

因此,您有很强的接口限制。方法find始终使用Key类型作为参数,如果不更改容器密钥类型,则无法对其进行更改。

如果您确定在初始化std::string时损失了太多时间,则可以使用缓冲区(如果没有线程)。例如:

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

现在,缓冲区在构造函数中只分配一次内存,而不是每次调用find时都分配。

换句话说,使用您自己的密钥类型,它可以使用std::string和const char*,但在这种情况下,您应该用您的密钥类型定义Hash(boost::hash<Key>)、谓词(std::equal_to<Key>)的实现。

类似这样的东西:

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

现在,您有一种方法可以获得const-char*并将其用于哈希和谓词。插入字符串时,您更喜欢使用StringKey。找到时-CharKey。

boost::unordered_map< Key , Domain::SomeObject, KeyHashFunctor, equal_to_Key > objectContainer;
void findStuff(const char* key) {
  auto it = objectContainer.find(CharKey(key));
}

但是,在这种情况下,添加虚拟函数和创建Key对象可能会降低性能,使用objectContainer变得不舒服。

如果您真的不想创建任何额外的std::字符串,您可以逐个运行所有键,并将它们与旧的strcmp进行比较。但在我看来,Kerrek解决方案是最好的

您可以继承boost::unordered_map,并添加一个find,该find的版本为"char*",用于处理临时std::字符串。

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

也要对以上内容持保留态度,因为我还没有测试过。我目前的设置VS2008与boost 1.40没有问题,馈送一个const char*查找(我也没有使用auto)。它确实存在const char*和operator[]函数的问题,我已经为允许访问的operator[]功能做了类似的事情,如objectContainer["key"]

//&lt---生成错误

什么错误?它应该按原样编译。不幸的是,没有简单的方法可以做你想做的事。我也遇到过同样的问题(

存在多个问题:find()的参数类型,std::equal_tostd::hashstd::less的类型

尝试使用这个:-

   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
  }