C++ STL Library: Introduction to String

C++ STL library

Learning method: Use the three realms of STL: usable, reasonable, and expandable.

Today we open a new topic: STL library of C++ data structure, we will introduce the usage and implementation process of commonly used libraries in STL library.

common library

library name

Required header files

data structure

string

#include<string>

string

vector

#include<vector>

dynamic array

list

#include<list>

Take the lead in doubly linked list

queue

#include<queue>

queue

stack

#include<stack>

the stack

therefore

#include<deque>

deque

priority_queue

#include<queue>

priority queue

string class

Introduction to the string class

Note: String in C++ is strictly a class, an object, not a type.

1. A string is a class representing a sequence of characters;

2. The standard string class provides support for this type of object, and its interface is similar to that of the standard character container, but adds design features specifically for manipulating single-byte character strings.

3. The string class is using char (ie as its character type, using its default char_traits and allocator types (see basic_string for more information on templates).

4. The string class is an instance of the basic_string template class. It uses char to instantiate the basic_string template class, and uses char_traits and allocator as the default parameters of basic_string (for more template information, please refer to basic_string).

5. Note that this class handles bytes independently of the encoding used: if it is used to process sequences of multi-byte or variable-length characters (such as UTF-8), all members of this class (such as length or size) and its will still operate on bytes (rather than actual encoded characters).

Summarize:

1.string is a string class that represents a string

2. The interface of this class is basically the same as that of conventional containers, and some conventional operations specially used to operate strings are added.

3. string is actually at the bottom: the alias of the basic_string template class, typedef basic_stringstring;

4. Cannot operate sequences of multi-byte or variable-length characters.

When using the string class, you must include #include header files and using namespace std;


Common constructions of string class objects

function name

Function Description

string() (emphasis)

Constructs an empty string class object, that is, an empty string

string(const char* s) (emphasis)

Use C-string to construct string class object

string(size_t n, char c)

The string class object contains n characters c

string(const string&s) (emphasis)

copy constructor

Example:

#include <iostream> #include <string>  using namespace std;  int main() {     string s1;         // 构造空的string类对象s1     string s2("i 1ove");  // 用C格式字符串构造string类对象s2     string s3(9, 'u');     string s4(s2);   return 0; }​

容量方法

The following are all class public member functions

method name

use

size (emphasis)

Returns the effective character length of the string

length

Returns the effective character length of the string

max_size

Returns the maximum number of characters supported by a string

resize (emphasis)

Change the number of valid characters to n, and fill the extra space with the character c

capacity (emphasis)

Return the total size of the space

reserve

request to change capacity, reserve space for string

clear (emphasis)

clear string

empty (emphasis)

Tests whether a string is empty

shrink_to_fit

Request that the string reduce its capacity to fit its size

Key examples:

// size/clear/resize void Teststring1() {   // 注意:string类对象支持直接用cin和cout进行输入和输出   string s("hello, World!!!");   cout << s.size() << endl;   cout << s.length() << endl;   cout << s.capacity() << endl;   cout << s << endl;   // 将s中的字符串清空,注意清空时只是将size清0,不改变底层空间的大小   s.clear();   cout << s.size() << endl;   cout << s.capacity() << endl;   // 将s中有效字符个数增加到10个,多出位置用'a'进行填充   // “aaaaaaaaaa”   s.resize(10, 'a');   cout << s.size() << endl;   cout << s.capacity() << endl;   // 将s中有效字符个数增加到15个,多出位置用缺省值'\0'进行填充   // "aaaaaaaaaa\0\0\0\0\0"   // 注意此时s中有效字符个数已经增加到15个   s.resize(15);   cout << s.size() << endl;   cout << s.capacity() << endl;   cout << s << endl;   // 将s中有效字符个数缩小到5个   s.resize(5);   cout << s.size() << endl;   cout << s.capacity() << endl;   cout << s << endl; }  //==================================================================================== void Teststring2() {   string s;   // 测试reserve是否会改变string中有效元素个数   s.reserve(100);   cout << s.size() << endl;   cout << s.capacity() << endl;   // 测试reserve参数小于string的底层空间大小时,是否会将空间缩小   s.reserve(50);   cout << s.size() << endl;   cout << s.capacity() << endl; } // 利用reserve提高插入数据的效率,避免增容带来的开销 //==================================================================================== void TestPushBack() {   string s;   size_t sz = s.capacity();   cout << "making s grow:\n";   for (int i = 0; i < 100; ++i)   {     s.push_back('c');     if (sz != s.capacity())     {       sz = s.capacity();       cout << "capacity changed: " << sz << '\n';     }   } } void TestPushBackReserve() {   string s;   s.reserve(100);   size_t sz = s.capacity();   cout << "making s grow:\n";   for (int i = 0; i < 100; ++i)   {     s.push_back('c');     if (sz != s.capacity())     {       sz = s.capacity();       cout << "capacity changed: " << sz << '\n';     }   } }

Notice:

1. The underlying implementation principle of size() and length() is exactly the same. The reason for introducing size() is to be consistent with the interfaces of other containers. In general, size() is basically used.

2.clear() just clears the valid characters in the string and does not change the size of the underlying space.

3. resize(size_t n) and resize(size_t n, char c) both change the number of effective characters in the string to n, the difference is that when the number of characters increases: resize(n) uses 0 to fill more The extra element space, resize(size_t n, char c) fills the extra element space with the character c. Note: When resize changes the number of elements, if the number of elements is increased, the size of the underlying capacity may be changed. If the number of elements is reduced, the total size of the underlying space remains unchanged.

4. reserve(size_t res_arg=0): Reserve space for string without changing the number of effective elements. When the parameter of reserve is smaller than the total size of the underlying space of string, reserver will not change the capacity.

access and traversal operations

function name

Function Description

operator[] (emphasis)

Returns the character at position pos, called by const string class object

begin+ end

begin gets an iterator for a character + end gets an iterator for the next position of the last character

rbegin + rend

begin gets an iterator for a character + end gets an iterator for the next position of the last character

scope for

C++11 supports a new traversal method for a more concise range for

Example code:

void Teststring(){
   
          string s1("hello World");       const string s2("Hello World");       cout << s1 << " " << s2 << endl;       cout << s1[0] << " " << s2[0] << endl;       s1[0] = 'H';       cout << s1 << endl;       // s2[0] = 'h'; 代码编译失败,因为const类型对象不能修改}void Teststring(){
   
          string s("hello World");       // 3种遍历方式:       // 需要注意的以下三种方式除了遍历string对象,还可以遍历是修改string中的字符,       // 另外以下三种方式对于string而言,第一种使用最多       // 1. for+operator[]       for (size_t i = 0; i < s.size(); ++i)       {
   
                 cout << s[i] << endl;       }       // 2.迭代器       string::iterator it = s.begin();       while (it != s.end())       {
   
                 cout << *it << endl;              ++it;       }       string::reverse_iterator rit = s.rbegin();       while (rit != s.rend())       {
   
                 cout << *rit << endl;       }       // 3.范围for       for (auto ch : s)       {
   
                 cout << ch << endl;       }}

Modification operations on class objects

function name

Function Description

push_back

Insert the character c at the end of the string

append

Append a string after a string

operator+= (emphasis)

Append the string str after the string

c_str (emphasis)

Returns a C format string

find + npos (key)

Find the character c from the position of the string pos backwards, and return the position of the character in the string

rfind

Find the character c from the position of the string pos forward, and return the position of the character in the string

substr

Start at position pos in str, intercept n characters, and return them

void Teststring(){
   
          string str;       str.push_back(' '); // 在str后插入空格       str.append("I"); // 在str后追加一个字符"I"       str += 'lov'; // 在str后追加一个字符'1ov'       str += "it"; // 在str后追加一个字符串"it"       cout << str << endl;       cout << str.c_str() << endl; // 以C语言的方式打印字符串       // 获取file的后缀       string file("string.cpp");       size_t pos = file.rfind('.');       string suffix(file.substr(pos, file.size() - pos));       cout << suffix << endl;       // npos是string里面的一个静态成员变量       // static const size_t npos = -1;       // 取出url中的域名       string url("http://www.cplusplus.com/reference/string/string/find/");       cout << url << endl;       size_t start = url.find("://");       if (start == string::npos)       {
   
                 cout << "invalid url" << endl;              return;       }       start += 3;       size_t finish = url.find('/', start);       string address = url.substr(start, finish - start);       cout << address << endl;       // 删除url的协议前缀       pos = url.find("://");           url.erase(0, pos + 3);       cout << url << endl;}

Notice:

1. When appending characters at the end of the string, the implementation methods of s.push_back(c) / s.append(1, c) / s += 'c' are similar. In general, the += operation of the string class is used for comparison Many, the += operation can not only concatenate single characters, but also concatenate strings.

2. When operating on string, if you can roughly estimate how many characters to put, you can first reserve the space through reserve

class non-member function

function

Function Description

operator+

Use it as little as possible, because the value is returned, resulting in low efficiency of deep copy

operator>> (emphasis)

Input operator overloading

operator<< (emphasis)

output operator overloading

getline (emphasis)

get a line of string

relational operators (emphasis)

size comparison

Mock implementation of string class

Classic string class problem

上面已经对string类进行了简单的介绍,只要能够正常使用即可。在面试中,面试官总喜欢让模拟实现string类,最主要是实现string类的构造、拷贝构造、赋值运算符重载以及析构函数。观察以下代码,判断该string类的实现是否有问题?

class string{
   
   public:       /*string()       :_str(new char[1])       {*_str = '\0';}       */           //string(const char* str = "\0") 错误示范       //string(const char* str = nullptr) 错误示范       string(const char* str = "")       {
   
                 // 构造string类对象时,如果传递nullptr指针,认为程序非法,此处断言下              if (nullptr == str)              {
   
                        assert(false);                     return;              }              _str = new char[strlen(str) + 1];              strcpy(_str, str);       }           ~string()       {
   
                 if (_str)              {
   
                        delete[] _str;                     _str = nullptr;              }       }private:       char* _str;};// 测试void Teststring(){
   
          string s1("hello bit!!!");              // string不明确       string s2(s1);                                    // string不明确}

上述string类没有显式定义其拷贝构造函数与赋值运算符重载,此时编译器会合成默认的,当用s1构造s2时,编译器会调用默认的拷贝构造。最终导致的问题是,s1、s2共用同一块内存空间,在释放时同一块空间被释放多次而引起程序崩溃,这种拷贝方式,称为浅拷贝。

浅拷贝

浅拷贝:也称位拷贝,编译器只是将对象中的值拷贝过来。如果对象中管理资源,最后就会导致多个对象共享同一份资源,当一个对象销毁时就会将该资源释放掉,而此时另一些对象不知道该资源已经被释放,以为还有效,所以 当继续对资源进项操作时,就会发生发生了访问违规。要解决浅拷贝问题,C++中引入了深拷贝。

深拷贝

深拷贝:如果一个类中涉及到资源的管理,其拷贝构造函数、赋值运算符重载以及析构函数必须要显式给出。一般情况都是按照深拷贝方式提供。

写时拷贝(了解)

写时拷贝就是一种拖延症,是在浅拷贝的基础之上增加了引用计数的方式来实现的。

引用计数:用来记录资源使用者的个数。在构造时,将资源的计数给成1,每增加一个对象使用该资源,就给计数增加1,当某个对象被销毁时,先给该计数减1,然后再检查是否需要释放资源,如果计数为1,说明该对象时资源的最后一个使用者,将该资源释放;否则就不能释放,因为还有其他对象在使用该资源。

现代写法的string

本处最主要是实现string类的构造、拷贝构造、赋值运算符重载以及析构函数。​具体完整的源码欢迎关注微信公众号“01编程小屋”,后台回复“C++String”获取完整源代码哦

class string{
   
   public:       string(const char* str = "")       {
   
                 if (nullptr == str)                     str = "";              _str = new char[strlen(str) + 1];              strcpy(_str, str);       }           string(const string& s)              : _str(nullptr)       {
   
                 string strTmp(s._str);              swap(_str, strTmp._str);       }           string& operator=(string s)       {
   
                 swap(_str, s._str);              return *this;       }         ~string()       {
   
                 if (_str)              {
   
                        delete[] _str;                     _str = nullptr;              }       }private:       char* _str;};

后续我们还会继续更新C++STL库的用法详解与原理,如果你喜欢我们的文章别忘了关注我们的公众号​“01编程小屋”哦!后续我们都会在上面更新最新的文章,关注小屋,学习编程不迷路。你的​支持就是我们坚持做下去的动力!

Guess you like

Origin blog.csdn.net/weixin_43654363/article/details/125793955