【问题标题】:Benefits of vector<char> over string?vector<char> 优于字符串的好处?
【发布时间】:2012-07-06 17:11:31
【问题描述】:

这个问题与this question 相关,但并不完全相同。

使用std::vector&lt;char&gt; 而不是std::string 来保存任意二进制数据有什么好处,除了与可读性相关的问题吗?

即与字符串相比,使用向量执行哪些任务更容易/更高效/更好?

【问题讨论】:

  • 在 C++03 std::string 中,其数据的连续性是有争议的。
  • @PlasmaHH:由于没有任何实现(据我所知)是不连续的,我愿意假设它对于这个问题是连续的。

标签: c++ string stl vector


【解决方案1】:

除了可读性(不应低估)之外,我还可以想到使用 std::string 而不是 std::vector 的几个小性能/内存问题:

  • 一些现代的std::string 实现使用small string optimization。如果你存储的数据大于string的内部缓冲区,就变成悲观了,降低了复制、移动和swap1的效率,增加sizeof()无用受益。

  • 一个高效的std::string 实现将始终分配比当前大小至少多 1 个字节来存储终止空值(不这样做需要在operator[] 中使用额外的逻辑来处理str[size()])。

我要强调的是,这两个问题都非常小;它们的性能成本很可能会在背景噪音中丢失。但你确实问过了。


1如果正在使用小字符串优化,这些操作需要在size() 上进行分支,而在良好的std::vector 实现中则不行。

【讨论】:

  • 关于小字符串的非常有趣的一点,虽然我还不相信这是一个缺点。 :) 不过,一个很好的答案,谢谢! +1
  • 您从哪里得到表明大多数实现使用小字符串的数据?在我看来,libstdc++ 并没有使用它,而且在过去十年我参与的几乎每个项目中,我一直在使用 libstdc++ ...
  • @PlasmaHH:我把它改成了“一些”。
  • 很多时候您需要将空终止字符串传递给旧版 API。 string 有 (string::c_str()) 但 vector 没有。这也是您需要额外空间的原因。
【解决方案2】:

除了可读性之外,并确保其他维护者不会混淆std::string 的目的,功能上并没有太大区别。如果效率是唯一的考虑因素,您当然也可以考虑 char*/malloc。

我能想到的一个潜在问题:

std::string 默认存储&lt;char&gt;。如果您以后需要处理另一种类型(例如 unsigned short),您可能需要:

  • 创建您自己的 typedef std::basic_string&lt;unsigned short&gt;(这会让您远离正常的 std::string 处理)
  • 尝试在 setter 中应用一些 reinterpret_cast 逻辑。

使用向量,您可以简单地将容器更改为std::vector&lt;unsigned short&gt;

【讨论】:

  • 你能扩展最后一部分吗?与std::vector&lt;unsigned short&gt;相比,使用std::basic_string&lt;unsigned short&gt;有什么缺点?
  • 一个缺点是它可能无法编译。 :-) std::char_traits&lt;unsigned short&gt; 不是标准要求的。
  • @Mehrdad 您的问题主要是对其他平台的可移植性以及与其他库的兼容性。您不再使用传统的 std::string,因为标准仅将 charwchar_t 定义为有效的 char_traits。如果您对内容运行字符串操作,则使用其他内容可能会导致未定义的行为。
【解决方案3】:

是的,vector&lt;char&gt; 确实确实string 拥有更多功能。

string 不同,vector&lt;char&gt; 保证在swap 操作期间保留迭代器、引用等。请参阅:May std::vector make use of small buffer optimization?

【讨论】:

    【解决方案4】:

    我认为这样做的唯一好处是可以轻松地增加字符的 std::vector,但即使这样也可以使用 std::string 来完成。

    您必须记住,即使 std::string 看起来像一个对象,它也可以像数组一样被访问,因此即使访问字符串的特定部分也可以在不使用 std::vector 的情况下完成

    【讨论】:

      【解决方案5】:

      理想情况下,人们会使用 vector&lt;unsigned char&gt; 来存储任意二进制数据 - 但我想你已经知道这一点 - 正如你提到的旧问题。

      除此之外,使用向量肯定会更节省内存,因为字符串会添加一个终止 Nul 字符。性能也可能会提高,因为两者的分配机制不同 - 向量保证连续内存!

      除此之外,使用字符串是不正确的,因为调用者/用户可能会无意中调用某些字符串方法,这可能是一场灾难。

      【讨论】:

      • 您介意扩展最后一段吗?什么是“灾难”?
      • 考虑一个例子:你有包含多个 nul 字符的二进制数据。如果用户调用 .length(),他会得到一些答案 - 这很可能是错误的,并且他永远不会被告知这是二进制数据而不是字符串这一事实。
      • 为什么错了?似乎您是在说它可以正常工作,只是它可能不可读(即具有误导性)。很好,但这不是我问题的重点——我特别提到了除了可读性问题。
      • @go4sri:在带有 nul 字符的字符串上调用 length() 应该会得到正确的长度。当用户开始使用c_str() 然后想知道为什么他们的字符串被截断时,就会出现问题。
      • @Mehrdad - 我认为这不符合可读性,但如果你不关心这种错误,那么你可以跳过它。
      【解决方案6】:

      正如其他答案所提到的,向量可能会稍微快一些,因为它保证了连续的内存,即使对于小尺寸也是如此,并且不会在末尾添加额外的空字节。但是,连接两个字符串比连接两个向量要简单得多(在代码方面):

      使用vector

      vector<char> a, b;
      // ...
      vector<char> c;
      c.insert(c.end(), a.begin(), a.end());
      c.insert(c.end(), b.begin(), b.end());
      

      使用string

      string a, b;
      // ...
      string c = a + b;
      

      【讨论】:

      • 这个问题要求vector&lt;char&gt;string 的好处,而不是相反...奇怪的是看到你只是在这方面引用其他答案,然后发布你自己的反面回复方向
      • 嗯,也许这更适合不同的问题。我回答的原因是,这是 Google 上“vector vs string”的第一个结果,所以我想我会添加一个答案,提出一些未提及的内容。
      • 哦,我明白了。是的,这很不幸,因为我已经列出了为什么我会使用string 而不是vector&lt;char&gt;,所以这不是我需要回答的问题。
      猜你喜欢
      • 2015-03-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-04-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多