2024-07-12
한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina
Table of contents
2. String class in the standard library
2.2 Common interface description of string class
1. Common construction of string class objects
2. Operations on string objects
3. Description of string structure under vs and g++
3. Simulation implementation of string class
3.5 Simulation implementation of string class
https://cplusplus.com/reference/string/string/?kw=string
- void Teststring()
- {
- string s1; // 构造空的string类对象s1
- string s2("hello bit"); // 用C格式字符串构造string类对象s2
- string s3(s2); // 拷贝构造s3
- }
PS:
- 1. size() andlength()The underlying implementation principle of the method is exactly the same.size()The reason is to keep consistent with the interface of other containers. Generally, size() is used.。
- 2. clear() just setsstringThe valid characters in the textarea are cleared without changing the size of the underlying space.
- 3. resize(size_t n) and resize(size_t n, char c)Both change the number of valid characters in the string tonThe difference is that when the number of characters increases: resize(n)use0To fill the extra element space,resize(size_t n, char c)Use characterscTo fill the extra element space. Note: resizeWhen changing the number of elements, if the number of elements is increased, the size of the underlying capacity may change. If the number of elements is reduced, the total size of the underlying space remains unchanged.
- 4. reserve(size_t res_arg=0):forstringReserve space without changing the number of valid elements.reserveThe parameter is less than
- stringWhen the total size of the bottom layer space isreserverThe capacity will not change.
The following structure is in 32 Verify on the platform. 32 Pointer occupancy under bit platform 4 bytes.vs. The structure of stringstring accounts for a total of 28 Bytes , the internal structure is a little more complicated, first There is a union, which is used to define Storage space for strings in string:
- When the string length is less than 16, an internal fixed character array is used to store
- When the string length is greater than or equal to16When the space is allocated from the heap
union _Bxty { // storage for small buffer or pointer to larger one value_type _Buf[_BUF_SIZE]; pointer _Ptr; char _Alias[_BUF_SIZE]; // to permit aliasing } _Bx;This design also makes sense. In most cases, the length of the string is less than 16 ,That string After the object is created, it already has 16 A fixed space for character arrays does not need to be created through the heap, which is highly efficient.Secondly: one size_t The field holds the length of the string, a size_t The field stores the total capacity of the space allocated from the heap.Finally: There is a pointer Do something else.Therefore, the total16+4+4+4=28bytes.![]()
g++ Down string StructureG++ Down, string This is achieved through copy-on-write. string The total number of objects 4 Bytes, which only contains a pointer, which will point to a heap space in the future, and contains the following fields:
- Total space size
- Valid string length
- Reference counting
- Pointer to the heap space used to store the string.
struct _Rep_base { size_type _M_length; size_type _M_capacity; _Atomic_word _M_refcount; };
PS: When implementing the string class yourself, you must pay attention to the shallow copy problem
- //string.h
- #pragma once
- #include<iostream>
- #include<assert.h>
- using namespace std;
- namespace mystr {
- class string
- {
- public:
- //迭代器, 因为字符串底层内存连续, 所以可以简单的定义成指针
- typedef char* iterator;
- typedef const char* const_iterator;
- //配合范围for循环
- iterator begin() { return _str; }
- iterator end() { return _str + _size; }
- //兼容常量字符串
- const_iterator begin() const { return _str; }
- const_iterator end() const { return _str + _size; }
- //string();
- string(const char* str = "");
- string(const string& s);
- string& operator=(string temp) { swap(temp); return *this; }
- ~string() { delete[] _str; _str = nullptr; _size = _capacity = 0; }
- //返回C语言字符数组
- const char* c_str() const { return _str; }
-
- size_t size() const { return _size; }
- char& operator[](size_t pos) { assert(pos < _size); return _str[pos]; }
- const char& operator[](size_t pos) const{ assert(pos < _size); return _str[pos]; }
- //重置大小
- void reserve(size_t n);
-
- void push_back(char ch) { insert(_size, ch); }
- void append(const char* str) { insert(_size, str); }
-
- string& operator+=(char ch) { insert(_size, ch); return *this; }
- string& operator+=(const char* str) { insert(_size, str); return *this; };
-
- void insert(size_t pos, char ch);
- void insert(size_t pos, const char* str);
- void erase(size_t pos = 0, size_t len = npos);
-
- size_t find(char ch, size_t pos = 0) {
- for (size_t i = pos; i < _size; i++) if (_str[i] == ch) return i;
- return npos;
- }
- size_t find(const char* str, size_t pos = 0) { return strstr(_str + pos, str) - _str; }
-
- void swap(string& s);
- string substr(size_t pos = 0, size_t len = npos);
-
- bool operator<(const string& s) const { return strcmp(_str, s._str) < 0; }
- bool operator>(const string& s) const { return !(*this <= s); }
- bool operator<=(const string& s) const { return !(*this > s); }
- bool operator>=(const string& s) const { return !(*this < s); }
- bool operator==(const string& s) const {return strcmp(_str, s._str) == 0; }
- bool operator!=(const string& s) const { return !(*this == s); }
- void clear() { _str[0] = '0'; _size = 0; }
-
-
- private:
- char* _str;
- size_t _size;
- size_t _capacity;
- //一般static变量的定义要放在类外, 整型是特例
- const static size_t npos = -1;
- };
- void swap(string& s1, string& s2);
- istream& operator>>(istream& ci, string& s);
- ostream& operator<<(ostream& co, string& s);
- }
-
- //string.cpp
- #include "string.h"
- namespace mystr {
- string::string(const char* str):_size(strlen(str)) {
- _str = new char[_size + 1];
- _capacity = _size;
- strcpy(_str, str);
- }
- string::string(const string& s) {
- string temp(s._str);
- swap(temp);
- }
- void string::reserve(size_t n) {
- if (_capacity < n) {
- char* temp = new char[n + 1];
- strcpy(temp, _str);
- delete[] _str;
- _str = temp;
- _capacity = n;
- }
- }
- void string::insert(size_t pos, char ch) {
- assert(pos <= _size);
- if (_size == _capacity) {
- size_t newcapacity = _capacity == 0 ? 4 : 2 * _capacity;
- reserve(newcapacity);
- }
- size_t end = _size + 1;
- while (end > pos) _str[end] = _str[end - 1], --end;
- _str[pos] = ch;
- _size++;
- }
- void string::insert(size_t pos, const char* str) {
- assert(pos <= _size);
- size_t len = strlen(str);
- if (_size + len > _capacity) reserve(_size + len);
- size_t end = _size + len;
- while (end > pos + len - 1) _str[end] = _str[end - len], --end;
- memcpy(_str + pos, str, len);
- _size += len;
- }
- void string::erase(size_t pos, size_t len) {
- if (len > _size - pos) _str[pos] = '0', _size = pos;
- else strcpy(_str + pos, _str + pos + len), _size -= len;
- }
- void string::swap(string& s) {
- char* temp = _str;
- _str = s._str;
- s._str = temp;
- std::swap(_size, s._size);
- }
- string string::substr(size_t pos, size_t len) {
- if (len > _size - pos) { string sub(_str + pos); return sub; }
- else {
- string sub;
- sub.reserve(len);
- for (size_t i = pos; i < pos + len; i++) sub += _str[i];
- return sub;
- }
- }
- void swap(string& s1, string& s2){ s1.swap(s2); }
- istream& operator>>(istream& ci, string& s) {
- s.clear();
- char ch = ci.get();
- while (ch != ' ' && ch != 'n') s += ch, ch = ci.get();
- return ci;
- }
- ostream& operator<<(ostream& co, string& s) {
- for (size_t i = 0; i < s.size(); i++) co << s[i];
- return co;
- }
- }
- //test.cpp
- #include "string.h"
- namespace mystr {
- void test1() {
- string s1 = "1111";
- string s2 = s1;
- cout << s1.c_str() << endl << s2.c_str() << endl;
- cout << s1.size() << endl;
- }
- void test2() {
- string s1 = "111";
- string s2 = "222222";
- s1 = s2;
- cout << s1.c_str() << endl;
- }
- void test3() {
- string s1 = "111222333";
- for (auto& i : s1) i += 3;
- cout << s1.c_str() << endl;
- const string s2 = "111222333";
- for (auto& i : s2) cout << i;
- cout << endl;
- for (size_t i = 0; i < s1.size(); i++) cout << (s1[i] += 2);
- cout << endl;
- }
- void test4() {
- string s1 = "sadfsf";
- s1.insert(2, '-');
- cout << s1.c_str() << endl;
- s1.insert(0, '-');
- cout << s1.c_str() << endl;
- s1.insert(2, "11111");
- cout << s1.c_str() << endl;
- s1.insert(0, "222222");
- cout << s1.c_str() << endl;
- }
- void test5() {
- string s1 = "asgfidsgf";
- s1.push_back('-');
- cout << s1.c_str() << endl;
- s1.append("=====");
- cout << s1.c_str() << endl;
- s1 += 'w';
- cout << s1.c_str() << endl;
- s1 += "0000";
- cout << s1.c_str() << endl;
- s1.erase(10);
- cout << s1.c_str() << endl;
- s1.erase(7, 100);
- cout << s1.c_str() << endl;
- s1.erase(3, 2);
- cout << s1.c_str() << endl;
- s1.erase(0);
- cout << s1.c_str() << endl;
- }
- void test6() {
- string s1 = "ksjfghks";
- cout << s1.find('h', 2) << endl;
- cout << s1.find("ghk", 2) << endl;
- cout << s1.find("ghksgs", 2) << endl;
- }
- void test7(){
- string s1 = "sggsdsdf";
- string s2 = "sdgfrgdb";
- cout << s1.c_str() << endl;
- cout << s2.c_str() << endl;
- swap(s1, s2);
- cout << s1.c_str() << endl;
- cout << s2.c_str() << endl;
- s1.swap(s2);
- cout << s1.c_str() << endl;
- cout << s2.c_str() << endl;
- string s3 = s1.substr(2, 5);
- cout << s3.c_str() << endl;
- }
- void test8() {
- string s1, s2;
- cin >> s1 >> s2;
- cout << s1 << endl << s2 << endl;
- }
- }
- int main() {
- mystr::test8();
- return 0;
- }