【问题标题】:C++ index into string map without allocationC ++索引到字符串映射而不分配
【发布时间】:2014-01-22 00:49:06
【问题描述】:

我正在编写一个具有不允许分配的高性能线程的应用程序。我有一张看起来像这样的地图:

map<String, MyCustomClass> objectCollection;

其中 String 是 std::string 的自定义包装器。我希望能够在高优先级线程上编写这样的代码:

int someValue = objectCollection["some string"].value;

当我这样做时,对数组的索引会导致构造一个字符串,这需要分配。我的想法是,我可能能够为我的地图定义一个自定义比较器,它可以接受一个 const char*,并且能够与一个字符串的 c 字符串胆量进行字符串比较。这可能吗?它看起来如何?

我可以用 String 实例做这样的事情:

String strTest = "";
const char* chars = strTest.chars();

【问题讨论】:

  • “某个字符串”是否总是一个常量或者可以是任何const char*
  • 如果你需要速度,你考虑过std::unordered_map吗?
  • @Nate Kohl "some string" 将按字面意思编程到代码中。绝对是一个常数。
  • @Borgleader 这将如何帮助我解决这个问题?
  • 是否所有的下标字符串都是提前知道的?你可以看看完美的哈希函数生成器(gperf)。

标签: c++ string memory-management


【解决方案1】:

你可以只做一次分配。

static const string Key("some string");
int someValue = objectCollection[Key];

零分配需要不同的字符串类。您会以某种方式使用const char* 和自定义比较机制。

【讨论】:

  • 抱歉,允许 0 个分配。不过感谢您的回答。
  • 不应该是static const string Key("some string");吗?
  • @ZECTBynmo:我怀疑你错过了这里的重点......另一个线程或操作系统加载程序可以在“高性能”线程启动之前构造 Key,后者可以重复分配新文本到它不会分配,除非比现有的capacity() 长。如果高性能线程不是非常短暂的,它可能会在启动时受到一次性分配的影响,但是知道许多后续分配(以及因此映射索引)操作将很快。如果有多个高性能线程,Key 可以成为线程特定的。
  • @timrau - 这两行实际上是相同的,当您声明变量并在同一行上使用 = 时,它不是赋值,而是调用复制构造函数。
  • 为了简洁起见,我将对其进行更改。
【解决方案2】:

自定义比较对地图没有任何好处;无论比较运算符如何工作,查找运算符始终将其参数转换为键类型。但是当您想要快速查找时,可能有更好的方法。

将事物保存在已排序的向量中并使用二分搜索算法(lower_bound() 等)查找它们通常比在地图中查找它们更快(因为除其他外,地图的内部树结构强加了很多每次查找时追逐的指针)。映射的插入比排序的向量快得多,但是当快速查找比快速插入更重要时,向量通常更快,并且向量的优点是可以使用异构比较函数(一个接受两个不同参数的函数)类型)。

类似这样的:

struct Element {
    std::string key;
    Thing value;
};

bool compare(const Element& lhs, const char* rhs) {
    return lhs.key < rhs;
}

using Collection = std::vector<Element>;

inline Thing lookup(const char* key, const Collection& coll) {
    // Requires coll to be already sorted
    auto i(std::lower_bound(coll.begin(), coll.end(), key, compare));
    if (i != coll.end() && i->key == key)
        return i->value;
    else
        return Thing();
}

【讨论】:

  • +1 用于建议可能是一个好的替代方案,尽管您没有提到一些主要缺点 - 特别是对于线程访问,排序向量中的对象可能在进一步插入期间移动可能很重要/擦除操作,而现有的 std::map 元素永远不会移动(即迭代器/指针未失效)。
  • 是的,排序向量方法非常适合您在程序的一个阶段构建数组,对其进行排序,然后在单独的阶段查找,没有(或很少) 插入或删除与查找交错。如果交错查询和更新很常见,那么 map 或 unordered_map 肯定更有效。
【解决方案3】:

在 C++14 中,有一些巧妙的新特性应该允许这种情况发生。例如,有一个模板化的地图::find

template< class K > iterator find( const K& x );

http://en.cppreference.com/w/cpp/container/map/find

【讨论】:

    【解决方案4】:

    您所能做的就是将 key_type 更改为 const char*,因为 map::find 以及 map::operator[] 以及 map::at 都将 key_type 作为参数。因此,即使您传递一个 const char* ,它也会在调用 map 函数之前构造一个 String 。因此,除非您将 String 设为静态,否则您将无法在不构建的情况下逃脱。

    【讨论】:

    • 有没有办法定义一个可以接受替代类型的替代比较运算符?
    • 是的pastebin.com/12mqXLpT 虽然这仍然会调用构造函数,你甚至可以将 const String& 作为参数,它也不会调用 String 构造函数问题是它被调用,因为 find/[]/at 需要一个字符串作为 arg
    • @ZECTBynmo map 的第三个参数是用户定义的比较器。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-10-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多