1

我试图通过将字符串放入 anunordered_set<string>然后在shared_ptr<string>'s. 很难知道何时删除了对集合中字符串的所有引用,所以我希望 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”。

emplace() 上的文档建议,但没有向我说明,该指针a可以在由指针分配引起的重新散列中幸存下来b。它似乎也保证了“foo”的第二个位置不会导致任何重新分配,因为它被认为已经存在于集合中。

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

更新 1

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

正如我在对@Peter R 的评论中提到的那样,我对移动语义、容器和引用甚至比现在更不舒服,而且很可能我没有编写简单的、基于字符串的解决方案来使用所有 C+ +11 可以提供。到现在为止,我似乎一直在绕一个大圈子旅行。

4

2 回答 2

1

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

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

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

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

于 2014-02-17T07:11:07.150 回答
1

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

  • string_pool本身存储string不参与共享所有权的 s,也没有任何方式在的引用计数达到 0string_pool时通知或更新shared_ptr

  • share_ptrs 彼此没有关系(你给他们两个原始指针而不是复制一个来制作另一个)

对于您的使用,您需要决定是否会在某个时间点主动erase从 中获取字符串string_pool,否则您可能需要在中放入 a并weak_ptr在使用之前string_pool检查共享是否仍然存在。string如果你还不熟悉这个概念,你可以谷歌weak_ptr。


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

  • 您的string变量是否尽可能通过引用传递,例如:const std::string&函数参数,只要您不会更改它们

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

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

  • 是否存在保留对 a 的引用的地方string,以及字符串中的偏移量会大大提高性能并减少内存使用量(引用的字符串必须保留,只要它是间接使用的) - 实现“ string_ref”是很常见的或类似的类是中型和大型 C++ 项目

于 2014-02-17T07:18:07.417 回答