将shared_ptr <string>用于unordered_set <string> </string> </string>

时间:2014-02-17 06:45:34

标签: c++ string shared-ptr unordered-set

我正在尝试通过将字符串放入unordered_set<string>然后传递shared_ptr<string>来减少字符串复制(已被测量为我的应用程序中的性能瓶颈)。很难知道何时删除了对集合中字符串的所有引用,所以我希望shared_ptr可以帮助我。这是未经测试的代码,说明了我希望如何编写代码:

unordered_set<string> string_pool;
 :
shared_ptr<string> a = &(*string_pool.emplace("foo").first); // .first is an iterator
 :
shared_ptr<string> b = &(*string_pool.emplace("foo").first);

在上面,只有一个字符串“foo”的实例应该在string_pool中; a和b都应指向它;并且在a和b都被破坏的时候,应该从string_pool中删除“foo”。

The doc on emplace()建议,但我没有告诉我,指针a可以在指针b的分配引起的重复中继续存在。它似乎也保证“foo”的第二个安置不会导致任何重新分配,因为它被识别为已经存在于集合中。

我在这里走在正确的轨道上吗?我需要让string_pool无休止地增长,但是没有一点可以简单地清楚()它,也没有明确的“所有者”字符串。

更新1

此问题的历史:这是一个“交通警察”应用程序,它从服务器读取数据,将数据包裹到其他服务器,接收他们的答案,将这些答案包裹给他人,接收,最后组装并返回摘要答案。它包括一个应用程序协议栈,它接收TCP消息,将它们解析为字符串标量值,然后应用程序将其组装成其他TCP消息,发送,接收等。我最初使用string编写它,{{1} } s和字符串引用, valgrind 报告了一个“高数字”的字符串构造函数(甚至使用 -O3 编译),以及集中在库例程中的高CPU使用率与字符串有关。我被要求研究减少字符串复制的方法,并设计了一个“memref”类( char * 和指向输入缓冲区的长度),可以复制它来代替字符串本身。然后出现了需要重复使用输入缓冲区的情况,而memrefs仍需要有效,所以我付钱将每个缓冲区子串复制到一个拘留区(vectors<string>),并在那里有memref点。然后我发现在进程区域可以一次性被清除(以防止其无限制地增长)时找到一个位置是困难和不方便的,并且我开始尝试重新设计拘留区域,以便当所有memrefs到实习字符串消失了,字符串将从池中删除。因此,shared_ptr。

正如我在对@Peter R的评论中提到的,我对移动语义,容器和引用的熟悉程度比现在还要低,而且我很可能没有编写简单的,基于字符串的解决方案来使用所有C ++ 11可以提供。到现在为止,我似乎已经在一个很棒的圈子里旅行了。

2 个答案:

答案 0 :(得分:1)

unordered_set拥有字符串。当它超出范围时,您的字符串将被释放。 我的第一印象是,您的方法听起来不会在可维护性或可测试性方面产生积极的体验。当然这个

shared_ptr<string> a = &(*string_pool.emplace("foo").first);

错了。您已经拥有unordered_set中字符串的所有者。尝试使用shared_ptr在其上放置另一个所有权层是行不通的。你可能有一个unordered_set<shared_ptr<string>>,但我甚至不推荐。

如果不了解代码库的其余部分,则很难在此处推荐“解决方案”。移动语义和传递const string&的组合应该能够处理低级别的大多数需求。如果仍然存在性能问题,那么它们可能是架构的。当然只使用shared_ptr<string>可能会解决您的生命周期问题,如果没有字符串的自然所有者,并且复制起来很便宜,在这种情况下不要使用unordered_set<string>

答案 1 :(得分:1)

你已经有点任性了。 shared_ptr在概念上形成一组对象的共享所有者......应使用shared_ptr创建第一个make_shared,然后自动创建其他副本(具有“值”语义)何时复制该值。你试图做的是有缺陷的:

  • string_pool本身存储了不参与共享所有权的string,也没有任何方式string_poolshared_ptr被通知或更新时{ {1}}的引用次数达到0

  • share_ptr s彼此没有任何关系(你给它们两个原始指针而不是复制一个来制作另一个)

根据您的使用情况,您需要决定是否在某个时间点主动erase来自string_pool的字符串,否则您可能需要weak_ptrstring_pool中,在使用之前检查共享string是否确实存在。如果你还不熟悉这个概念,你可以google weak_ptr。


另外,值得检查您当前观察到字符串复制是否是性能问题是由于编码效率低下。例如:

  • 您的string变量是可能的参考文件,例如:const std::string&}函数参数,只要您不更改它们

  • 您是否使用static const string而不是字符串文字/字符数组的连续运行时重新创建?

  • 您是否正在使用合理的优化级别进行编译(例如-O2,/ O2)

  • 是否存在保持对string的引用的地方,并且字符串中的偏移将大大提高性能并减少内存使用(只要间接使用,引用的字符串必须保持不变) - 为这个中型和大型C ++项目实现“string_ref”或类似的类是很常见的