【问题标题】:avoid temporary std::string to invoke boost::unordered_map::find避免临时 std::string 调用 boost::unordered_map::find
【发布时间】:2012-02-25 12:40:59
【问题描述】:

我有以下类型:

 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 临时需要有自己的缓冲区,复制@ 987654330@ 内容,然后使用它来运行find() 方法。

我可以使用快捷方式来避免在此处创建std::string 临时地址吗?

【问题讨论】:

  • 我不确定“临时”是否是正确的词。你是某种星际迷航的人吗?
  • @KerrekSB:星际迷航与它有什么关系? “时间”是一个真实的词,尽管您说得对,在这里使用它不是正确的。
  • 感谢修复,我时不时会和西班牙语混在一起
  • “星际迷航”...“轨道上的轻盈竞赛”...哈哈(LRiO 肯定一直在为这个机会祈祷...

标签: c++ boost stdstring unordered-map


【解决方案1】:

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

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

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

【讨论】:

  • Kerrek,所以如果我从你写的内容中正确推断,你会说你对我的问题的回答是“不要费心避免临时的,传递一个 const std::string 可能暗示编译器要通过神奇的手段来避免“缓冲区分配”?
  • @lurscher:没有魔法。您通过 const 引用而不是值传递字符串,因此您不会复制任何内容,而是引用现有字符串。当然,您必须在其他地方有一个现有的字符串。
  • @lurscher - Kerrek 避免临时的方法是首先没有 const char* 参数。如果你到处使用std::string,你就不需要任何转换!
  • 也许我想要的是一种类型,它是 std::string 的某种变体和一个不可变的类字符串类型,只有一个 const char* 的引用(用户负责const char*)
  • @lurscher:也许吧。我们是谁来告诉你的想法......但是你需要在该类型上键入地图,而不是在std::string上。地图拥有它的关键对象。如果你不喜欢这样,你可能需要一个不同的容器。
【解决方案2】:

主要问题是你的容器的声明。

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

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

其他方式,使用您自己的密钥类型,它可以使用 std::string 和 const char *,但在这种情况下,您应该使用您的密钥类型定义 Hash(boost::hash&lt;Key&gt;)、谓词 (std::equal_to&lt;Key&gt;) 的实现.

类似这样的:

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 变得很不舒服。

【讨论】:

    【解决方案3】:

    如果你真的不想创建任何额外的 std::string,你可以一个一个地遍历所有的键,并将它们与旧的 strcmp 进行比较。但在我看来,Kerrek 解决方案是最好的

    【讨论】:

    • 最佳解决方案是什么?我在问是否有办法避免临时。一对一的比较完全破坏了 unordered_map 的要点,它应该具有 O(1) 访问权限
    【解决方案4】:

    您可以继承 boost::unordered_map 并添加一个带有“char *”版本的查找,它为您处理临时 std::string。

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

    由于我还没有测试过,所以也对上述内容持保留态度。我当前的带有 boost 1.40 的设置 VS2008 在输入 const char * 来查找时没有问题(我也没有使用 auto)。它确实存在 const char * 和 operator[] 函数的问题,我对 operator[] 函数做了类似的操作,允许像 objectContainer["key"]

    进行访问

    【讨论】:

      【解决方案5】:

      //

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

      存在多个问题:find()的参数类型、std::equal_to、std::hash和std::less的类型

      【讨论】:

        【解决方案6】:

        尝试使用这个:-

           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
          }
        

        【讨论】:

          猜你喜欢
          • 2016-09-04
          • 1970-01-01
          • 2014-01-11
          • 1970-01-01
          • 2013-02-06
          • 2012-05-23
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多