vector<char>相对于string的优势是什么?

29

这个问题与这个问题有关,但不完全相同。

除了与可读性相关的问题之外,使用std :: vector<char>代替std :: string来保存任意二进制数据是否有任何好处?

也就是说,与使用字符串相比,是否有任何易于执行/更有效率/更好的任务可以使用向量来完成?


2
在C++03中,std::string的数据连续性是有争议的。 - PlasmaHH
@PlasmaHH:由于我不知道任何不连续的实现方式,所以我愿意假设它在这个问题中是连续的。 - user541686
6个回答

26

除了易读性(不应低估)之外,我可以想到一些使用 std::string 而非 std::vector 的一些小型性能/内存问题:

  • 一些现代的 std::string 实现采用了小字符串优化。如果你存储的数据大于 string 内部缓冲区的大小,则会导致劣化,降低复制、移动和 swap 的效率1,并增加 sizeof() 的大小而没有任何好处。

  • 一个高效的 std::string 实现将始终分配至少比当前大小多 1 个字节以存储终止 null(如果不这样做,则需要在 operator[] 中额外处理 str[size()])。

我应该强调,这两个问题都非常小;它们的性能成本很可能会被淹没在背景噪音中。但是您确实提出了这个问题。


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


非常有趣的关于小字符串的观点,虽然我还没有被说服它是一个缺点。 :) 不过,这是一个很好的答案,谢谢!+1 - user541686
你从哪里得到的数字表明大多数实现使用小字符串?在我看来,libstdc++并没有使用它,在过去十年中我参与的几乎每个项目中,我都在使用libstdc++... - PlasmaHH
@PlasmaHH:我已经将它更改为“一些”。 - JoeG
很多时候,你需要向传统API传递以空字符结尾的字符串。字符串有string::c_str(),但向量没有。这就是为什么你需要额外的空间。 - Remus Rusanu

2

1
除了确保另一个维护者不会混淆std::string的目的之外,功能上没有太大的区别。当然,如果效率是唯一的考虑因素,您也可以考虑char*/malloc。
我能想到的一个潜在问题是: std::string默认存储<char>。如果您以后需要处理另一种类型(例如unsigned short),您可能需要执行以下操作之一:
- 创建自己的typedef std::basic_string<unsigned short>(这将使您远离正常的std::string处理) - 在setter中暂时应用一些reinterpret_cast逻辑。
使用向量,您只需将容器更改为std::vector<unsigned short>即可。

你能详细说明最后一部分吗?与使用std::vector<unsigned short>相比,使用std::basic_string<unsigned short>的缺点是什么? - user541686
一个缺点是它可能无法编译。 :-) std::char_traits<unsigned short> 不是标准所必需的。 - Bo Persson
@Mehrdad,你的问题主要是可移植性到其他平台和与其他库的兼容性。你不再使用传统的std::string,因为标准只定义了charwchar_t作为有效的char_traits。如果你在内容上运行字符串操作,使用其他东西可能会导致未定义的行为。 - seanhodges

1
正如其他答案提到的,向量可能会稍微快一些,因为它保证连续的内存,即使对于小的大小也是如此,并且不会在末尾添加额外的空字节。但是,连接两个字符串比连接两个向量要简单得多(从代码角度来看):
使用向量
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<char>相对于string的优势,而不是反过来...看到你只是引用其他答案并在这个方面发表自己的回答,有点奇怪。 - user541686
嗯,也许这更适合另一个问题。我回答的原因是这是“vector<char> versus string”的谷歌搜索结果中的第一个,所以我想加入一些未提及的内容。 - Matthew D. Scholefield
哦,我明白了。是的,这很不幸,因为我已经列出了一长串为什么我会使用string而不是vector<char>的原因,所以这并不是我需要回答的问题。 - user541686

0

我认为你从中唯一获得的好处就是可以轻松地递增字符的std::vector,但即使如此,也可以使用std::string来完成。

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


0

理想情况下,我们应该使用vector<unsigned char>来存储任意二进制数据 - 但我认为你已经知道这一点了 - 因为你提到了旧问题。

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

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


您介意详细说明一下最后一段吗?什么是“灾难”? - user541686
考虑一个例子:您有包含多个空字符的二进制数据。如果用户调用 .length(),他将得到一些答案 - 这很可能是错误的,并且他永远不会意识到这是二进制数据而不是字符串。 - go4sri
为什么是错的?看起来你是在说它可以正常工作,除非它可能无法阅读(即具有误导性)。那很好,但这不是我的问题的重点 - 我明确表示除了可读性之外还存在问题。 - user541686
@go4sri:在一个带有空字符的字符串上调用 length() 应该会给出正确的长度。问题出现在用户开始使用 c_str(),然后想知道为什么他们的字符串被截断了。 - tinman
@Mehrdad - 我认为这不属于可读性问题,但如果您并不关心此类错误,则可以跳过它。 - go4sri

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接