关于c ++:Vector vs string

Vector vs string

C++STD::vector和STD::Basic字符串之间的根本区别是什么?


  • Basic字符串不调用其元素的构造函数和析构函数。向量确实如此。

  • 交换基本字符串会使迭代器失效(启用小字符串优化),交换向量则不会。

  • 在C++ 03中,基本字符串内存可能不会被连续分配。向量总是连续的。此差异在C++0x[Strun.Adv]中删除:


    The char-like objects in a basic_string object shall be stored contiguously

  • 基本_字符串具有字符串操作接口。向量没有。

  • Basic字符串可以使用复制写策略(在C++ 11中)。向量不能。

非信徒相关引用:

[基本字符串]:

The class template basic_string conforms to the requirements for a Sequence Container (23.2.3), for a
Reversible Container (23.2), and for an Allocator-aware container (Table 99), except that basic_string
does not construct or destroy its elements using allocator_traits::construct and allocator_-
traits::destroy and that swap() for basic_string invalidates iterators. The iterators supported
by basic_string are random access iterators (24.2.7).


basic_string提供了编译器和标准库实现,在矢量上有一些自由:

  • "小字符串优化"对字符串有效,它允许实现在字符串较短时将实际字符串(而不是指向字符串的指针)存储在字符串对象中。沿着这条线的东西:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    class string
    {
        size_t length;
        union
        {
            char * usedWhenStringIsLong;
            char usedWhenStringIsShort[sizeof(char*)];
        };
    };
  • 在C++ 03中,底层数组不必是连续的。在当前的标准下,以"绳子"的形式实现basic_string是可能的。(尽管没有人这样做,因为这会使成员std::basic_string::c_str()std::basic_string::data()的实施成本过高。)C++ 11现在禁止这种行为。

  • 在C++ 03中,EDCOX1(1)允许编译器/库供应商使用对数据的写入(可以保存在副本上),这对于EDCOX1 2是不允许的。在实践中,这一点曾经非常普遍,但由于它对多线程的影响,现在已经不那么普遍了。然而,无论哪种方式,您的代码都不能依赖于是否使用COW实现std::basic_string。C++ 11现在再次禁止这种行为。

  • 在EDOCX1 1中也有一些辅助方法,但是大多数都是简单的,当然可以很容易地在EDOCX1,12的上面实现。


    关键的区别在于,当std::basic_string无法保存数据时,std::vector应将其数据保存在连续内存中。因此:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    std::vector<char> v( 'a', 3 );
    char* x = &v[0]; // valid

    std::basic_string<char> s("aaa" );
    char* x2 = &s[0];     // doesn't point to continuous buffer
    //For example, the behavior of
    std::cout << *(x2+1);
    //is undefined.
    const char* x3 = s.c_str(); // valid

    在实践中,这种差异并不那么重要。


    tldr:strings被优化为只包含字符原语,vectors可以包含原语或对象。

    vectorstring之间最显著的区别是vector能够正确地包含对象,string只在原语上工作。因此,vector提供的这些方法对于string使用原语是无用的:

  • 向量::ESPACE
  • 矢量::放回原处
  • 矢量::~矢量
  • 即使扩展string也不允许它正确地处理对象,因为它缺少析构函数。这不应被视为缺点,它允许对vector进行显著优化,因为string可以:

  • 做短字符串优化,潜在地避免堆分配,几乎不增加或不增加存储开销
  • 使用char_traits作为string的模板参数之一,定义如何对所包含的原语(其中只实现charwchar_tchar16_tchar32_t)执行操作:http://en.cppreference.com/w/cpp/string/char_traits)
  • 特别相关的是char_traits::copychar_traits::movechar_traits::assign,显然意味着将使用直接分配,而不是构造或破坏,这对原始人来说更为可取。所有这些专业化都会给string带来额外的缺点,即:

  • 只使用charwchar_tchar16_tchar32_t原语类型。显然,32位大小的原语可以使用其同等大小的char_type:https://stackoverflow.com/a/3555016/2642059,但是对于诸如long long这样的原语,需要编写char_traits的新专门化,以及专门化char_traits::eofchar_traits::not_eof的想法,而不只是使用vector。似乎不是最好的时间利用方式。
  • 由于短字符串优化,迭代器被所有可能使vector迭代器失效的操作都失效,但string迭代器又被string::swapstring::operator=失效。
  • vectorstring界面的其他差异:

  • 没有可变的string::data:为什么std::string.data()不提供可变的char*?
  • string提供了处理vector中没有的单词的功能:string::c_strstring::lengthstring::appendstring::operator+=string::comparestring::replacestring::substrstring::copystring::findstring::rfind、EDOCX1 1〔50〕、EDOCX11〔51〕、EDOCX11〔51〕、EDOCX11〔41〕41〔41〔41〕、EDOCX11〔42〕、EDOCX11〔43〕、EDOCX11〔44〕44、string::replace、EDOCX11〔46〕46、EDOCX11〔46〕、EDOCX11〔46〕47、1〔52〕、string::find_last_not_ofstring::operator+string::operator>>string::operator<<string::stoistring::stolstring::stollstring::stoulstring::stoullstring::stofstring::stodstring::stoldstirng::to_stringstring::to_wstring
  • 最后,无论在哪里,vector接受另一个vector的论点,string接受stringchar*的论点。
  • 注意,这个答案是针对C++ 11编写的,所以EDCOX1×0的S需要被连续地分配。


    std::stringstd::vector之间的一个区别是,程序可以从以空结尾的字符串构造字符串,而使用向量则不能。

    1
    2
    std::string a ="hello";          // okay
    std::vector<char> b ="goodbye";  // compiler error

    这通常使字符串更容易使用。


    基本的_字符串提供了许多特定于字符串的比较选项。您是对的,因为底层内存管理接口非常相似,但是字符串包含许多额外的成员,比如c_str(),对于向量来说这是没有意义的。


    矢量是模拟数组的数据结构。它的内部实际上是一个(动态)数组。

    基本的字符串类表示一系列字符。它包含序列的所有常规操作,另外,它还包含标准字符串操作,如搜索和连接。

    可以使用vector保留所需的任何数据类型std::vector or or even std::vector< std::vector >,但basic_string只能用于表示"文本"。