当前位置:网站首页>The underlying implementation of string

The underlying implementation of string

2022-07-06 21:24:00 Lonely, Monan

String Underlying implementation


 

string stay C++ It is also an important knowledge , But I want to use it well , You need to know how its bottom layer is written , In order to better use this string, So let's do it this time string The bottom of the , however string There are many interface functions , We cannot achieve it all at once , The main thing to realize this time is its common interface , And important interfaces The functions realized this time are :string Constructor for , copy constructor , Destructor , iterator ( It is divided into const And non const Two versions ),reserve,push_back,append,+=( It is divided into += Characters and strings ),clear,swap, Stream insertion , Stream output ,c_str,size,capacity,empty,resize,[] overloaded ( Not for const And non const Two versions ),<,<=,>,>=,==,!= overloaded ,find( It is divided into two versions: search character and string )insert( There are two versions of insert character and insert string ),erase.( As for how many have been achieved , Not here , Quite a lot of ...


First, get ready :  Because it needs to be implemented separately string The bottom of the , Therefore, in order to avoid the connection with string Conflict , So we encapsulate it in a separate namespace , Secondly, its four private members :_str( Store string ),_capacity( Record the capacity ),_size( Record valid characters ),npos( It is needed in some functions )


 

One : Constructors

1 Its effective number and size is its length , use strlen Calculation is enough .

2 Open a space ( here +1 To give \0 Reserved location   When opening space, you must give \0 One more )

3 Copy the string to the open space

1         string(const char* str = "")
2             :_size(strlen(str))
3             , _capacity(_size)
4         {
5             _str = new char[_capacity + 1];//+1 It's for  '\0'  Leave a place  string Open space must be more than one position 
6             strcpy(_str, str);
7         }

 

Two : Copy structure

Copy structures are divided into : Traditional writing and modern writing

The traditional way of writing : The structure is the structure , The copy is the copy

1 Its effective number and size is its length , use strlen Calculation is enough .

2 Open a space ( to \0 Open one more space )

3 Copy the string to this space

4 Assign this space to _str 

5 It's size And capacity And s Sync

 1         string(const string& s)
 2             :_size(strlen(s._str))
 3             ,_capacity(_size)
 4         {
 5             char* tmp = new char[_capacity + 1];
 6             strcpy(tmp, s._str);
 7             _str = tmp;
 8             _size = s._size;
 9             _capacity = s._capacity;
10         }

Modern writing : utilize tmp Copy , Let them Exchange

1 Because the copy structure is copied to a nonexistent , So initialize them first , So that they can exchange

2 utilize tmp Construct a string that needs to be copied

3 let _str And tmp In exchange for

        string(const string& s)
            :_str(nullptr)
            ,_size(0)
            ,_capacity(0)
        {
            string tmp(s._str);
            swap(tmp);
        }

( Modern writing is more recommended here )

 

3、 ... and : Destructor

 1 When str Not empty

2 Release , And leave it empty , Then set its valid characters and size 0

1         ~string()
2         {
3             if (_str)
4             {
5                 delete[] _str;
6                 _str = nullptr;
7                 _size = _capacity = 0;
8             }
9         }

 

Four : Assignment overload

It is divided into traditional writing and modern writing ① and ②

The traditional way of writing

1 When you don't assign values to yourself

2 Open a space

3 Copy the string into the space

4 release _str Space

5 hold tmp Space assigned to _str

6 And then _str The valid characters and size of the assigned string are the same

7 return

 1         string& operator=(const string &s)
 2         {
 3             if (this != &s)
 4             {
 5                 char* tmp = new char[s._capacity + 1];
 6                                strcpy(tmp, s._str);
 7                 delete[] _str;
 8                 _str = tmp;
 9                 _size = s._size;
10                 _capacity = s._capacity;
11             }
12             return *this;
13         }    

Modern writing ①

1 utilize tmp Construct a string

2 Give Way _str And tmp In exchange for

3 return

1         string& operator=(const string &s)
2         {
3             string tmp(s._str);
4             swap(tmp);
5             return *this;
6         }

Modern writing ②

1 There's something special here , Because it needs direct exchange without change s The data of , There is no need to quote , Instead, it returns by passing a value

2 hold _str Exchange with string

3 return

1         string& operator=(string s)
2         {
3             swap(s);
4             return *this;
5         }

 

5、 ... and :swap

Because it is necessary to complete the exchange operation of three private members , therefore swap Exchange three private members directly in

Here we need to use the Library , But the compiler will default to use the swap, So we need to add std, Use the Library swap

1         void swap(string& s)
2         {
3             std::swap(_str, s._str);
4             std::swap(_size, s._size);
5             std::swap(_capacity, s._capacity);
6     }

 

6、 ... and :c_str

Because stream insertion has not been implemented , So the demonstration can print with this function

Because this function just prints , Without changing the string , So add const, Prevent unexpected changes

1         const char* c_str()const
2         {
3             return _str;
4          }

 

7、 ... and :reserve

This function is specially used for capacity expansion .

1 When the required value is greater than space , It needs to be expanded

2 Create a space ( by \0 Open one more space )

3 hold _str Copy to new space

4 And then _str Space release

5 Assign the new space to _str

6 Put the new size capacity Change to the expanded size

 1         void reserve(size_t n)
 2         {
 3             if (n > _capacity)
 4             {
 5                 char* tmp = new char[n + 1];
 6                 strcpy(tmp, _str);
 7                 delete[] _str;
 8                 _str = tmp;
 9                 _capacity = n;
10             }
11         }

 

8、 ... and :push_back

This function is used to insert a character at the end

1 First judge whether the space is full

2 utilize reserve Open space ( There are special circumstances here : Sometimes the space we open is 0  Then continue with 2 Double expansion , It cannot be expanded (0*n=0)  So when capacity by 0 when   Capacity expansion 4  If not for 0  Double expansion

3 After capacity expansion or when capacity expansion is not required   Add the characters to be added in the place of valid characters

4 Then move the valid characters back

5 Add again \0  Otherwise, there is no \0  Can't stop

 1         void push_back(char c)
 2         {
 3             if (_size == _capacity)
 4             {
 5                 reserve(_capacity == 0 ? 4 : _capacity * 2);
 6             }
 7             _str[_size] = c;
 8             ++_size;
 9             _str[_size] = '\0';
10                  }

 

Nine :+= heavy load

In practical use ,+= With the function of push_back identical , also += It is more convenient , So we need to provide += The function of

1 Because the actual function is the same , It can be reused directly push_back that will do  

2 Because you need to support continuous += So we need to go back

1         string& operator+=(char c)
2         {
3             push_back(c);
4             return *this;
5         }

 

Ten :append

This function is used to add a string

1 Calculate the valid characters and the length of the string to be added

2 If the length of the valid character and the string to be added is greater than the actual space

3 So we need to expand , Expand string length + Valid character length is enough

4 Copy the string to the end of the valid character

6 The valid characters are also changed to valid characters and the length of the string to be added

 1         void append(const char* str)
 2         {
 3             int len = _size+strlen(str);
 4             if (len > _capacity)
 5             {
 6                 reserve(len);
 7             }
 8             strcpy(_str+_size, str);
 9             _size = len;    
10                 }            

 

11、 ... and :+= overloaded

+= The addition of strings is also better than append Use more times , So we also need to provide

The actual functions here are the same , So reuse directly

1 Because you want to support continuous +=, So we need to go back

1         string& operator+=(const char* str)
2         {
3             append(str);
4             return *this;
5         }

 

Twelve :clear

Used to clear data

Clear data , But there is no room to shrink , Just clear the data in the space , This is something to be aware of

1 Add... In the first place \0  When printing \0  Will stop , The following data cannot be printed

2 The effective number is modified to 0

1         void clear()
2         {
3             _str[0] = '\0';
4             _size = 0;
5     }

 

13、 ... and : Provide query size

This function provides private members size Size

Because there is no need to modify , So add const

1         size_t size()const
2         {
3             return _size;
4         }

 

fourteen : Provide query capacity

This function provides private members capacity Size

Because there is no need to modify , So add const

1         size_t capacity()const
2         {
3             return _capacity;
4         }

 

15、 ... and :empty

It provides the function of judging empty

1 When _str When the string is empty   return true

2 When _str When it is not an empty string   return false

 1         bool empty()const
 2         {
 3             if (_str == "")
 4             {
 5                 return true;
 6             }
 7             else
 8             {
 9                 return false;
10             }
11         }

 

sixteen :resize

function : Capacity expansion , And initialize

When the size to be expanded , Smaller than the actual size , Then it is necessary to put the actual size - To expand the unused space, clear the data

1 The size of Dangdang to be expanded , Smaller than the actual size

2size Change to the size to be expanded

3 Add \0

4 When the size to be expanded is larger than the actual size

5 Capacity expansion n Size

6 from Actual valid characters Start , Until the actual space size ends

7 All revised to c ( If you don't pass parameters , The default is \0)

8 The actual valid characters are changed to n

9 Change the valid characters to \0

 1         void resize(size_t n, char c = '\0')
 2         {
 3             // When n Less than size when 
 4             if (n < _size)
 5             {
 6                 _size = n;
 7                 _str[_size] = '\0';
 8             }
 9             else// When n Greater than size when 
10             {
11                 if (n > _capacity)
12                 {
13                     reserve(n);
14                 }
15                 
16                 for (size_t i = _size; i < n; i++)
17                 {
18                     _str[i] = c;
19                 }
20                 _size = n;
21                 _str[_size] = '\0';// Add characters   Manually add \0
22             }
23         }

 

seventeen :[] heavy load

This function is divided into non const Version and const edition

Not const edition

1 The size to be accessed cannot exceed valid characters   Need to assert

2 return _str The value of the corresponding subscript

1         char& operator[](size_t index)
2         {
3             assert(index < _size);
4 
5             return _str[index];
6         }

const edition

In some places, the access subscript does not need to be modified , So we need to provide const edition

1         const char& operator[](size_t index) const
2         {
3             assert(index < _size);
4 
5             return _str[index];
6         }

 

eighteen :<,<=,>,>=,==,!= overloaded

Use here strcmp() function   if _str<s._str  return <0 Value   Equal return 0  Greater than return >0 Value

And other functions can be reused directly

 1         bool operator<(const string& s)
 2         {
 3             return strcmp(_str, s._str) < 0;
 4         }
 5 
 6         bool operator<=(const string& s)
 7         {
 8             return _str < s._str || strcmp(_str, s._str) == 0;
 9         }
10 
11         bool operator>(const string& s)
12         {
13             return strcmp(_str, s._str) > 0;
14         }
15 
16         bool operator>=(const string& s)
17         {
18             return _str>s._str|| strcmp(_str, s._str) == 0;
19         }
20 
21         bool operator==(const string& s)
22         {
23             return strcmp(_str, s._str) == 0;
24         }
25 
26         bool operator!=(const string& s)
27         {
28             return !(_str == s._str);
29         }

 

nineteen :find

function : return c stay string The first place in

1 from pos Start looking at the location , If characters are found c  return , If the cycle ends , It means no , return npos( representative -1)

 1         size_t find(char c, size_t pos = 0) const
 2         {
 3             assert(pos <= _size);
 4             for (; pos <= _size; pos++)
 5             {
 6                 if (_str[pos] == c)
 7                 {
 8                     return pos;
 9                 }
10             }
11             return npos;
12         }

 

twenty :find

Function returns substring s stay string The first place in

Use here strstr function , Find string s

If not found   Returns an empty   You need to determine

If it is empty , return npos

If not be empty   Return to where it first appeared  

First occurrence -_str(*)

 

 1         size_t find(const char* s, size_t pos = 0)
 2         {
 3             const char* p = strstr(_str + pos, s);
 4             if (p == nullptr)
 5             {
 6                 return npos;
 7             }
 8             else
 9             {
10                 return p - _str;
11             }
12         }

 

The 21st :insert

function : stay pos Insert character in position c, And return the position of the character

1 First judge whether the space is full

2 When it is full, it needs to be expanded ,  A special case   When capacity by 0 when   Capacity expansion 4  When not for 0 when ,2 Double expansion

3 Define index end Start after valid characters (\0 Later on   Valid characters are recorded \0)

4 Move a number back , end Forward , Continue to move the next number

5 When you reach the position where you need to insert , stop it

6 At the position to be inserted   Insert characters c

7 Valid characters +1

8 return

        string& insert(size_t pos, char c)
        {
            assert(pos <= _size);
            if (_size == _capacity)
            {
                reserve(_capacity == 0 ? 4 : _capacity * 2);
            }

            size_t end = _size + 1;
            while (end > pos)
            {
                _str[end] = _str[end-1];
                --end;
            }
            _str[pos] = c;
            ++_size;

            return *this;
        }

 

Twenty-two insert

function : stay pos Insert string at position str, And return the position of the character

1 When the position to be inserted is greater than the valid character   It needs to be asserted that

2 Calculate the length of the added string

3 If the length of valid characters plus the added string is greater than the actual size

4 The length of the expanded valid characters plus the added string is greater than the actual size

5 Define index end From valid characters +len ( This is to have enough space to insert strings )

6 When end here we are pos+len-1 Stop where you are

7 Move each character len A place  

8end--  Continue to move to the next position

9 use strncpy function , Copy the string in

10 Valid characters plus the length of the string

11 return

 1         string& insert(size_t pos, const char* str)
 2         {
 3             assert(pos <= _size);
 4             size_t len = strlen(str);
 5             if (len+_size > _capacity)
 6             {
 7                 reserve(len+_size);
 8             }
 9 
10             size_t end = _size + len;
11             while (end>pos+len-1)//-1 It's because of one \0
12             {
13                 _str[end] = _str[end-len];
14                 end--;
15             }
16             strncpy(_str + pos, str, len);
17             _size += len;
18 
19             return *this;
20         }

 

23 :erase

1 When the position to be deleted is greater than the valid character   To assert

2 When the position is not given or the length to be deleted is greater than the valid characters

3 Directly in pos Position plus \0  Delete directly pos Later data

4 The valid characters are modified to pos

5 If it is not greater than the valid character , When you want to delete some strings

6 Give Way begin from pos+len( Start at the end of the string to be deleted )

7 Cover the front   from begin-len Start overlay at )

8begin++  Continue to begin The number of covers the front

9 until begin There are valid characters

10 Valid characters minus the length of the string to be deleted

11 Add \0  Always delete , Add characters these cannot be added automatically \0 Of   Must be added manually \0

12 return

 1         string& erase(size_t pos, size_t len=npos)
 2         {
 3             assert(pos < _size);
 4             if (pos == npos || pos + len > _size)
 5             {
 6                 _str[pos] = '\0';
 7                 _size = pos;
 8             }
 9             else
10             {
11                 int begin = pos + len;
12                 while (begin <  _size)
13                 {
14                     _str[begin - len] = _str[begin];
15                     ++begin;
16                 }
17             }
18             _size -= len;
19             _str[_size] = '\0';
20 
21             return *this;
22         }

 

Twenty-four : iterator

Divided into non const Version and const edition

Not const edition

take char*  Rename it to  iterator

The iterator is  begin end

begin Returns the first

Go straight back to _str that will do

end Return tail

Add valid characters to the return header

 1                 typedef char* iterator;
 2 
 3         iterator begin()
 4         {
 5             return _str;
 6         }
 7 
 8         iterator end()
 9         {
10             return _str + _size;
11         }

 

const edition

speak char*  Rename it to  const_iterator

I just have to add const that will do

 1 typedef const char* const_iterator;
 2         const_iterator begin() const// To provide const And non const Two versions 
 3         {
 4             return _str;
 5         }
 6 
 7         const_iterator end() const
 8         {
 9             return _str + _size;
10         }

 

twenty-five : Stream insertion 、 Stream extraction

Stream extraction

Because you need to match , So it needs to be implemented outside the class

1 Because continuous extraction should be supported   So want to use ostream& As return type

2 Use return for  Print with this

3 return

1     ostream& operator<<(ostream& out, const string& s)
2     {
3         for (auto k : s)
4         {
5             out << k;
6         }
7         return out;
8     }

 

Stream insertion

Because you need to match , So it needs to be implemented outside the class

1 Create a character

2 Characters are used to extract   Because characters cannot be separated by spaces   To prevent conflict   So we need get  In exchange for behavioral segmentation

3 establish buff Array   Initialize to \0

4 Define index  i

5 When not with spaces   When changing behavior conditions

6 Put the characters into the array respectively

7 When the array is full  

8 Say that the array is added as a string s

9 Let's talk about it again buff All overloads are \0

10 Index overload is 0

11 After the end of the cycle , Continue inserting into ch

12 When there are less than full characters left , Add to s Inside

13 return

    istream& operator>>(istream& in, string& s)
    {
        char ch;
        ch = in.get();
        char buff[128] = { '\0' };
        size_t i = 0;
        while (ch != '  ' && ch != '\n')
        {
            buff[i++] = ch;
            if (i == 127)
            {
                s += buff;
                memset(buff, '\0', 128);
                i = 0;
            }
            ch = in.get();
        }
        s += buff;
        return in;
    }

 

Here we add two easy-to-use functions

to_string  Let's talk about the conversion from integer to string

1     int i = 123456;
2     string s1 = to_string(i);

stoi  Let's talk about string conversion to integer

1     int n = stoi(s1);

This is the whole content of this article , If it helps you , Hope to get your praise !

 

原网站

版权声明
本文为[Lonely, Monan]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/187/202207061259463609.html