代码之家  ›  专栏  ›  技术社区  ›  Dervin Thunk

C++ STD中的字符串类是如何工作的?

  •  7
  • Dervin Thunk  · 技术社区  · 14 年前

    恐怕我不知道模板(或者C++),但我知道算法和数据结构(甚至一些OOP!):)总之,为了使问题更准确一点,考虑一下我想成为答案的一部分(还有一些我事先不知道的问题)。

    1. 为什么它被编码为模板?
    2. 模板如何工作?
    3. 如何分配内存?
    4. 为什么(不是)优于仅以空结尾的字符数组?
    5 回复  |  直到 6 年前
        1
  •  16
  •   Ian R. O'Brien Mamedov    8 年前
    1. std::string 实际上是 typedef 到A std::basic_string<char> 你的答案就在上面。它是一个模板,以便 basic_string 几乎所有事情都要处理。 char , unsigned char , wchar_t , pizza ,不管… string 它本身只是一个程序员使用的便利 烧焦 作为数据类型,因为这是经常需要的。

    2. 按要求无法回答。如果你对某件事感到困惑,请尽量缩小范围。

    3. 有两个答案。一,从应用层的角度来看,所有 基本字符串 对象使用 allocator 对象执行实际分配。分配方法可能因实现而异,也可能因模板参数不同而有所不同,但实际上它们将使用 new 在较低级别分配和管理包含的资源。

    4. 由于各种原因,它优于单字符数组。

      • 一串 为你管理记忆。在向字符串添加或删除数据时,不必分配缓冲区空间。如果添加的缓冲区超过当前分配的缓冲区的容量, 一串 会在幕后为你重新分配。

      • 在这方面, 一串 可以看作是一种智能指针。出于同样的原因,智能指针比原始指针更好, 一串 s优于原始字符数组。

      • 类型安全。这似乎有点复杂,但 一串 正确使用比字符缓冲区具有更好的类型安全性。考虑一个常见的场景:

     #include <string>
     #include <sstream>
     using namespace std;
    
     int main()
     {
       const char* jamorkee_raw = "jamorkee";
    
       char raw_buf[0x1000] = {};
       sprintf( raw_buf, "This is my string.  Hello, %f", jamorkee_raw);  
    
       const string jamorkee_str = "jamorkee";
       stringstream ss;
       ss << "This is my string.  Hello " << jamorkee_str; 
       string s = ss.str();
     }
    

    使用raw char缓冲区时甚至不可能出现上面提到的类型安全问题 一串 和小溪一起。

        2
  •  7
  •   Community skywinder    7 年前

    回答一些问题的速度相当快(因此可能不完整):

    1. 为什么它被编码为模板?

    模板提供了类函数处理任意数据类型的能力。例如 basic_string<> 模板类可以处理 char 单位(即 std::string typedef)或 wchar_t 单位( std::wstring )或任何吊舱类型。使用除 烧焦 瓦查特 是不寻常的( std::vector<> 更可能被使用),但这种可能性存在。

    1. 如何分配内存?

    本标准未规定。事实上, 基本字符串<gt; 模板允许使用一个任意的分配器来实际分配内存(但不确定在什么点上可能请求分配)。有些实现可能将短字符串存储在实际的类成员中,并且只在字符串超过某个大小时动态分配。请求的大小可能正是存储字符串所需的大小,也可能是允许增长而不需要重新分配的大小的倍数。

    其他信息被盗自 another SO answer :

    Scott Meyer's book, Effective STL, 有一章是关于std::string实现的,这是对常见变化的一个很好的概述:“第15项:注意字符串实现中的变化”。

    他谈到了4种变化:

    • 引用计数的实现(通常称为“写入时复制”)上的几个变体-当字符串对象被复制为未更改时,引用计数将增加,但实际的字符串数据不会增加。两个对象都指向相同的refcounted数据,直到其中一个对象对其进行修改,从而导致数据的“写入时复制”。这些变化包括存储refcount、锁等内容的位置。

    • “短字符串优化”实现。在这个变量中,对象包含指向数据、长度、动态分配缓冲区大小等的普通指针。但是,如果字符串足够短,它将使用该区域来保存字符串,而不是动态分配缓冲区。

    1. 为什么(不是)优于仅以空结尾的字符数组?

    单向 string 类优于仅以空结尾的数组,因为类管理所需的内存,因此减少了涉及分配错误或超出分配数组末尾的缺陷。另一个(可能是次要的)好处是可以在字符串中存储“空”字符。缺点是可能会有一些开销,特别是你必须依赖于字符串类的动态内存分配。在大多数可能不是主要问题的场景中,对于某些设置(例如嵌入式系统),这可能是一个问题。

        3
  •  2
  •   Steve Townsend    14 年前
    1. string 不是模板, 一串 basic_string 的类模板 char . 它是一个模板,因此例如,您可以typedef wstring 它专门处理宽字符,并对封装值使用所有相同的代码。

    2. 参见@gman的评论。 编译时间 代码重用,同时保留选择性特殊情况的能力,是模板的基本原理。

    3. 依赖于实现。有些执行单实例分配,具有写时复制功能。有些对小字符串使用内置缓冲区,只有在达到一定大小后才从堆中分配。我建议您通过遍历构造函数和后续代码来研究它在编译器上的工作方式。 <string> ,因为这将帮助您理解2。动手,这比仅仅阅读它更有价值(尽管一本书或其他阅读是介绍模板的好主意)。

    4. 因为 const char* 支持它的CRT是不小心的人的一个虫子农场。看看你免费得到的所有东西 std::string . 加一 whole bunch of Standard C++ algorithms 与之合作 一串 迭代器。

        4
  •  2
  •   dan04    14 年前

    为什么它被编码为模板?

    有几个人给出了答案 std::basic_string 成为模板意味着你可以同时拥有 std::basic_string<char> std::basic_string<wchar_t> . 没有人解释的是为什么C和C++在一开始就有多个字符类型。

    C,特别是在早期版本中,对数据类型的要求是最低的。为什么有 bool 当整数0和1正常工作时?当“byte”和“character”都是8位时,为什么有不同的类型?

    问题是,8位将您限制为256个字符,这对于英语或俄语这样的字母语言来说是足够的,但对于日语或汉语来说却远远不够。现在我们有了21位代码点的Unicode。但是 char 无法扩展到16或32位,因为假设 烧焦 =字节是如此根深蒂固。所以我们有一个单独的“宽字符”类型。

    但现在我们有个问题 wchar_t 在Linux上是utf-32,在Windows上是utf-16。并解决 那个 问题:C++标准的下一个版本将添加 char16_t char32_t 类型(以及相应的字符串类型)。

        5
  •  0
  •   Zeke    14 年前

    一个好的免费在线资源是Bruce Eckel的“C++思维”,他的网站在这里: http://mindview.net/Books/TICPP/ThinkingInCPP2e.html .

    他的免费书的第二卷反映在这里: http://www.smart2help.com/e-books/ticpp-2nd-ed-vol-two/#_ftnref14 . 第三章是关于字符串类,为什么它是一个模板,为什么它有用。