当前位置:网站首页>STL -- common function replication of string class

STL -- common function replication of string class

2022-07-08 00:49:00 New Young

Preface :

  • In this paper, STL-string Duplication of commonly used functions in

  • Data collected by bloggers New Young, In the serial .

  • Questions included by bloggers :New Young

  • Reprint please indicate the source :New Young

string First knowledge of class

  1. string The essence is basic_string Rename the instantiated template class , It contains many member functions that handle strings : Replanted [],= etc.
typedef basic_string<char> string;

Namespace

I'm copying string Class time , because string Class is a built-in type in the standard library , To avoid naming pollution , You can name your own namespace

// complete string Add, delete, check, modify, duplicate 
namespace My_Str // To prevent pollution std Namespace 
{
	class string
	{
	private:
		char* _str;
		int _size;// Number of valid characters 
		int _capacity;// The capacity of valid characters , It doesn't contain '\0', But because when opening up space, open up one more ,
					  // Therefore, one is reserved by default '\0', Easy to carry out C function 
        ......
 };

Data member

Here we use array form , Convenient operation

namespace My_Str // To prevent pollution std Namespace 
{
	class string
	{
	private:
		char* _str;
		int _size;// Number of valid characters 
		int _capacity;// The capacity of valid characters , It doesn't contain '\0', But because when opening up space, open up one more ,
					  // Therefore, one is reserved by default '\0', Easy to carry out C function 

Constructors

  1. string The standard cannot use a single character in initialization , You can only use strings or existing objects .

  2. It is recommended to use Modern writing , It makes use of the automatic destruction of local variables after the frame of function stack and the flexible reuse of code

Custom constructors

  1. All default constructors , For empty strings ,_size by 0, Pay attention to when expanding
// All default constructors , For empty strings ,_size by 0, Pay attention to when expanding 
//string(const char* str="");
My_Str::string::string(const char* str)
	:_size(strlen(str)), _capacity( _size)
{
	_str = new char[_capacity+1];//+1 It's for \0 Reserve space , prevent 
	strcpy(_str, str);
}

copy constructor

  1. Without reference , The transfer of arguments to formal parameters is also a copy
  2. When there are members who need dynamic management , Prevent shallow copy from causing multiple attacks on the same space delete problem
  3. Modern writing , The essence is the reuse of code and the post frame destruction of local variable function stack
// Copy structure , Be careful 
// 1.  Without reference ,  The transfer of arguments to formal parameters is also a copy 
// 2. When there are members who need dynamic management , Prevent shallow copy from causing multiple attacks on the same space delete problem 
My_Str::string::string(const string& s)
	
{
	 General writing 
	//_str = new char[strlen(s._str) + 1];
	//strcpy(_str, s._str);
	//_size = s._size;
	//_capacity = s._capacity;

	 Modern writing , The essence is the reuse of code and the post frame destruction of local variable function stack 
	string tmp(s._str);// A custom constructor was called 
	_str = nullptr;// This step must have , Otherwise, the random values are delete
	swap(tmp);//string Under the swap function 
	//std::swap(_str,tmp._str);// Under the standard library swap template function 
	_size = tmp._size;
	_capacity = tmp._capacity;

}

Assignment operator

  1. Generally, we need to consider the problem of self assignment

  2. Modern writing , Because the address of the copied object is different , Therefore, there is no need to consider the problem of self assignment and releasing the same space multiple times

My_Str::string& My_Str::string::operator=(const My_Str::string& s)
{
	// Assignment of itself 
	//if (&s != this)
	//{
	//	// General writing :
	//	char *tmp = new char[s._size + 1];// Prevent application failure ,C++ Of new Would throw exceptions , Not learned 
	//	strcpy(tmp, s._str);
	//	delete[]_str;// Release the original space 
	//	_str = tmp;// After the local variable is destroyed , Heap space still exists .
	//	_size = s._size;
	//	_capacity = s._capacity;
	//}

	// Modern writing , There is no need to consider the problem of self assignment and releasing the same space multiple times 
		string tmp(s);//
		std::swap(_str, tmp._str);
		_size = tmp._size;
		_capacity = tmp._capacity;
		return *this;

}

Destructor

My_Str::string::~string()// Destructor 
{
	delete[]_str;
	_str = nullptr;
	_size =_capacity= 0;

}

c_str()

const char* My_Str::string::c_str()
{
	return _str;
}

const char* My_Str::string::c_str()const 
{
	return _str;
}

clear()

void My_Str::string::clear()
{
    
	_size = 0;
}

size()

size_t My_Str::string::size()
{
	return _size;
}


size_t My_Str::string::size()const 
{
	return _size;
}

The operator []

char& My_Str::string::operator[](size_t pos)
{

	assert(pos < _size);
	return _str[pos];
}

const char& My_Str::string::operator[](size_t pos)const
{
	assert(pos < _size);

	return _str[pos];
}

iterator

iterator , For the time being, the pointer

typedef char* iterator;
typedef const char* const_iterator;

My_Str::string::iterator My_Str::string::begin()
{
	return _str;
}
My_Str::string::iterator My_Str::string::end()
{
	return _str + _size ;

}

My_Str::string::const_iterator My_Str::string::begin()const
{
	return _str;
}
My_Str::string::const_iterator My_Str::string::end()const
{
	return _str + _size;

}

Expansion function

reserve()

Scaling down is not supported , So just think about n>_capacity The situation of

void My_Str::string::reserve(size_t n)
{
	if(n > _capacity)	
	{
		char* tmp = new char[n+1];
		strcpy(tmp,_str);
		delete[]_str;
		_str = tmp;
		_capacity = n;
	}
}

resize()

Support shrinking and expanding , So we need to size As a boundary , Consideration

void  My_Str::string::resize(size_t n, char ch)
{
	//resize Scaling down is not supported _capacity;
	if (n <= _size)
	{
		_str[n] = '\0';
		_size = n;
	}
	else 
	{
		if (n > _capacity)
		{
			reserve(n);
		}
		memset(_str + _size, ch, n - _size);
		_str[_size] = '\0';
	}
}

Insert

Tail insertion

  1. Single character , Just expand the capacity according to the situation 2 Times ,
  2. But for Strings , Its number cannot be empty , Therefore, the expansion depends on the situation .
  3. It is more recommended to use +=;

push_back()

void My_Str::string::push_back(char ch)
{

	if (_size == _capacity)
	{
		reserve(_capacity==0?4:_capacity*2);
	}
	_str[_size] = ch;
	++_size;
	_str[_size] = '\0';
}

append()

void  My_Str::string::append(const char* str)
{
	size_t len = strlen(str);
	if ((len + _size) > _capacity)
	{
	
		reserve(len + _size);
	}
	strcpy(_str + _size, str);
}

The operator +=

My_Str::string& My_Str::string::operator +=(const char ch)
{
	push_back(ch);
	return *this;
}

My_Str::string& My_Str::string::operator +=(const char* str)
{
	append(str);
	return *this;
}

Head insertion

insert()

Head insertion , It is generally not recommended to use , Low efficiency

My_Str::string& My_Str::string::insert(size_t pos, const char ch)
{
	assert(pos <= _size);
	if (_size == _capacity)
	{
		reserve(_capacity == 0 ? 4 : _capacity * 2);
	}
	// Because it is an unsigned integer , In the subtraction operation, we should pay attention to the problem of dead circulation 
	size_t end = _size+1;
	while (end > pos)
	{
		_str[end] = _str[end - 1];
		--end;
	}
	_str[pos] = ch;
	return *this;
}
My_Str::string& My_Str::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)
	{
		_str[end] = _str[end - len];
		--end;
	}
	strncpy(_str + pos, str,len);
	//strcpy Will '\0 Add in '
	return *this;
}

check

find()

size_t My_Str::string::find(char ch)
{
	for (size_t i = 0; i < _size; ++i)
	{
	
		if (ch == _str[i])
		{
			return i;
	}
	}
	return npos;
}
size_t My_Str::string::find(const char* str, size_t pos)
{
	assert(pos < _size&& strlen(str)<_size);
	const char* ret = strstr(_str, str);
	if (ret != nullptr)
	{
		return ret - _str;
	}
	return npos;
}

Delete

erase()

My_Str::string& My_Str::string::erase(size_t pos , size_t len )
{
	assert(pos < _size);

	if (len == npos || len >= (_size - pos))// Delete all 
	{
		_str[pos] = '\0';
		_size = pos;
	}
	else 
	{
		strcpy(_str + pos, _str + pos + len);
		_size -= len;
	}
	return *this;
}

I / O function

operator<<()

std::ostream& operator<<(std::ostream& out, const My_Str::string& s)
{
	for (int i = 0; i < s.size(); ++i)// Finite cycles , You can avoid strings containing '\0' The situation of 
	{	
		out << s[i];
	}
	//cout<<s.c_str();
	return out;
}

operator>>()

std::istream& operator >> (std::istream& in,  My_Str::string& s)
{
	char ch = 0;
	//ch = getchar();
	//while (ch != ' '&&ch!='\n')
	//{
	//	s += ch;
	//	ch = getchar();

	//}
	s.clear();
	ch = in.get();
	while (ch != ' '&&ch!='\n')
	{
		s += ch;
		ch = in.get();
	}
	return in;
}

Comparison function

because string There are a lot of interfaces for , Here, overloaded functions are defined as global functions

operator<()

//"abcd" "abcd" false
//"abcd" "abcde"true
//"abcde" "abcd"false
bool operator<(const My_Str::string& s1, const My_Str::string& s2)
{
	size_t i1 = 0;
	size_t i2 = 0;

	while ( i1< s1.size()&& i2<s2.size())
	{
		if (s1[i1] < s2[i2])
		{
			return false;
		
		}
		++i1;
		++i2;
	}

	return i1 < s1.size() ? false : true;

}

operator==()

bool operator==(const My_Str::string& s1, const My_Str::string& s2)
{
	size_t i1 = 0;
	size_t i2 = 0;
	while (i1 < s1.size() && i2 < s2.size())
	{
		if (s1[i1] != s2[i2])
		{
			return false;
		}
		++i1;
		++i2;
	}
	return i1 == s1.size() && i2 == s2.size() ? true : false;
}

operator!=()

bool operator!=(const My_Str::string& s1, const My_Str::string& s2)
{
	return !(s1 == s2);
}

operator<=()

bool operator<=(const My_Str::string& s1, const My_Str::string& s2)
{
	return s1 < s2 || s1 == s2;
}

operator>()

bool operator>(const My_Str::string& s1, const My_Str::string& s2)
{
	return !(s1 <= s2);
}

operator>=()

bool operator>=(const My_Str::string& s1, const My_Str::string& s2)
{
	return !(s1 < s2);
}

All the code

String.h

#pragma once
#include<iostream>
#include<string>
#include<assert.h>
// complete string Add, delete, check, modify, duplicate 
namespace My_Str // To prevent pollution std Namespace 
{
	class string
	{
	private:
		char* _str;
		int _size;// Number of valid characters 
		int _capacity;// The capacity of valid characters , It doesn't contain '\0', But because when opening up space, open up one more ,
					  // Therefore, one is reserved by default '\0', Easy to carry out C function 
	public:
		static const size_t npos;
		

		// All default constructors , Cannot assign with null pointer , There will be a wild pointer problem 
		string(const char* str="");
		
		// Custom copy construction ,
		// 1.  Without reference ,  The transfer of arguments to formal parameters is also a copy 
		// 2. The default copy structure is shallow copy , When there are members who need dynamic management , Prevent shallow copy from causing multiple attacks on the same space delete problem 
		// This is also the reason for modern writing 
		string(const string& s);
		
		// Destructor 
		~string();

		void swap(string& s);

		// Assignment operator 
		string& operator=(const string& s);
		// The first address of the character .
		const char* c_str();
		const char* c_str()const;
		size_t size();
		size_t size()const ;

		char& operator[](size_t pos);
		const char& operator[](size_t pos)const;
		
		// iterator , For the time being, the pointer 

		// Ordinary objects overlap 
		typedef char* iterator;
		iterator begin();
		iterator end();

		// Regular object 
		typedef const char* const_iterator;
		const_iterator begin()const;
		const_iterator end()const;


		// Capacity expansion 
		void reserve(size_t n);// Scaling down is not supported 
		void resize(size_t n, char ch='\0');// Support shrinking and expanding 


        // Insert , It's more about use +=
		// Head insertion , It is generally not recommended to use , Low efficiency 
		string& insert(size_t pos, const char ch);
		string& insert(size_t pos, const char *str);


		// Tail insertion ,
		// Single character , Just expand the capacity according to the situation 2 Times ,
		//  But for Strings , Its number cannot be empty , Therefore, the expansion depends on the situation .
		//
		void push_back(char ch);

		void append( const char* str);
		

		string& operator +=(const char ch);

		string& operator +=(const char* str);
		
		// Delete 
		string& erase(size_t pos = 0, size_t len = npos);
		// check 
		size_t find(char ch);
		size_t find(const char* str, size_t pos = 0);

	};
}

std::ostream &operator<<(std::ostream& out, const My_Str::string& s);

std::istream& operator >> (std::istream& in,  My_Str::string& s);

bool operator<(const My_Str::string& s1, const My_Str::string& s2);
bool operator==(const My_Str::string& s1, const My_Str::string& s2);
bool operator!=(const My_Str::string& s1, const My_Str::string& s2);

bool operator<=(const My_Str::string& s1, const My_Str::string& s2);


bool operator>(const My_Str::string& s1, const My_Str::string& s2);

bool operator>=(const My_Str::string& s1, const My_Str::string& s2);

String.cpp

#define _CRT_SECURE_NO_WARNINGS
#include"String.h"

 const size_t My_Str::string::npos=-1;

// All default constructors , For empty strings ,_size by 0, Pay attention to when expanding 
My_Str::string::string(const char* str)
	:_size(strlen(str)), _capacity( _size)
{
	_str = new char[_capacity+1];
	strcpy(_str, str);
}

// Copy structure , Be careful 
// 1.  Without reference ,  The transfer of arguments to formal parameters is also a copy 
// 2. When there are members who need dynamic management , Prevent shallow copy from causing multiple attacks on the same space delete problem 
// 3. This is also the reason for modern writing 
My_Str::string::string(const string& s)
	
{
	 General writing 
	//_str = new char[strlen(s._str) + 1];
	//strcpy(_str, s._str);
	//_size = s._size;
	//_capacity = s._capacity;

	 Modern writing , The essence is the reuse of code and the post frame destruction of local variable function stack 
	string tmp(s._str);// A custom constructor was called 
	_str = nullptr;// This step must have , Otherwise, the random values are delete
	swap(tmp);//string Under the swap function 
	//std::swap(_str,tmp._str);// Under the standard library swap template function 
	_size = tmp._size;
	_capacity = tmp._capacity;

}


My_Str::string::~string()// Destructor 
{
	delete[]_str;
	_str = nullptr;
	_size =_capacity= 0;

}

void My_Str::string::swap(string& s)
{
	std::swap(_str, s._str);
	std::swap(_size, s._size);
	std::swap(_capacity, s._capacity);
}

My_Str::string& My_Str::string::operator=(const My_Str::string& s)
{
	// Assignment of itself 
	//if (&s != this)
	//{
	//	// General writing :
	//	char *tmp = new char[s._size + 1];// Prevent application failure ,C++ Of new Would throw exceptions , Not learned 
	//	strcpy(tmp, s._str);
	//	delete[]_str;// Release the original space 
	//	_str = tmp;// After the local variable is destroyed , Heap space still exists .
	//	_size = s._size;
	//	_capacity = s._capacity;
	//}

	// Modern writing , There is no need to consider the problem of self assignment and releasing the same space multiple times 
		string tmp(s);//
		std::swap(_str, tmp._str);
		_size = tmp._size;
		_capacity = tmp._capacity;
		return *this;

}

// The first address of the character .
const char* My_Str::string::c_str()
{
	return _str;
}

const char* My_Str::string::c_str()const 
{
	return _str;
}

size_t My_Str::string::size()
{
	return _size;
}


size_t My_Str::string::size()const 
{
	return _size;
}


char& My_Str::string::operator[](size_t pos)
{

	assert(pos < _size);
	return _str[pos];
}

const char& My_Str::string::operator[](size_t pos)const
{
	assert(pos < _size);

	return _str[pos];
}



My_Str::string::iterator My_Str::string::begin()
{
	return _str;


}
My_Str::string::iterator My_Str::string::end()
{
	return _str + _size ;

}


My_Str::string::const_iterator My_Str::string::begin()const
{
	return _str;
}
My_Str::string::const_iterator My_Str::string::end()const
{
	return _str + _size;

}

void My_Str::string::reserve(size_t n)
{
	if(n > _capacity)	
	{
		char* tmp = new char[n+1];
		strcpy(tmp,_str);
		delete[]_str;
		_str = tmp;
		_capacity = n;
	}
}

void  My_Str::string::resize(size_t n, char ch)
{
	//resize Scaling down is not supported _capacity;
	if (n <= _size)
	{
		_str[n] = '\0';
		_size = n;
	}
	else 
	{
		if (n > _capacity)
		{
			reserve(n);
		}
		memset(_str + _size, ch, n - _size);
		_str[_size] = '\0';
	}
}

void My_Str::string::push_back(char ch)
{

	if (_size == _capacity)
	{
		reserve(_capacity==0?4:_capacity*2);
	}
	_str[_size] = ch;
	++_size;
	_str[_size] = '\0';
}

void  My_Str::string::append(const char* str)
{
	size_t len = strlen(str);
	if ((len + _size) > _capacity)
	{
	
		reserve(len + _size);
	}
	strcpy(_str + _size, str);
}

My_Str::string& My_Str::string::operator +=(const char ch)
{
	push_back(ch);
	return *this;
}

My_Str::string& My_Str::string::operator +=(const char* str)
{
	append(str);
	return *this;
}

size_t My_Str::string::find(char ch)
{
	for (size_t i = 0; i < _size; ++i)
	{
	
		if (ch == _str[i])
		{
			return i;
	}
	}
	return npos;
}
size_t My_Str::string::find(const char* str, size_t pos)
{
	assert(pos < _size&& strlen(str)<_size);
	const char* ret = strstr(_str, str);
	if (ret != nullptr)
	{
		return ret - _str;
	}
	return npos;
}
My_Str::string& My_Str::string::insert(size_t pos, const char ch)
{
	assert(pos <= _size);
	if (_size == _capacity)
	{
		reserve(_capacity == 0 ? 4 : _capacity * 2);
	}
	// Because it is an unsigned integer , In the subtraction operation, we should pay attention to the problem of dead circulation 
	size_t end = _size+1;
	while (end > pos)
	{
		_str[end] = _str[end - 1];
		--end;
	}
	_str[pos] = ch;
	return *this;
}
My_Str::string& My_Str::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)
	{
		_str[end] = _str[end - len];
		--end;
	}
	strncpy(_str + pos, str,len);
	//strcpy Will '\0 Add in '
	return *this;
}
My_Str::string& My_Str::string::erase(size_t pos , size_t len )
{
	assert(pos < _size);

	if (len == npos || len >= (_size - pos))// Delete all 
	{
		_str[pos] = '\0';
		_size = pos;
	}
	else 
	{
		strcpy(_str + pos, _str + pos + len);
		_size -= len;
	}
	return *this;
}
//
//"abcd" "abcd" false
//"abcd" "abcde"true
//"abcde" "abcd"false
bool operator<(const My_Str::string& s1, const My_Str::string& s2)
{
	size_t i1 = 0;
	size_t i2 = 0;

	while ( i1< s1.size()&& i2<s2.size())
	{
		if (s1[i1] < s2[i2])
		{
			return false;
		
		}
		++i1;
		++i2;
	}

	return i1 < s1.size() ? false : true;

}
bool operator==(const My_Str::string& s1, const My_Str::string& s2)
{
	size_t i1 = 0;
	size_t i2 = 0;
	while (i1 < s1.size() && i2 < s2.size())
	{
		if (s1[i1] != s2[i2])
		{
			return false;
		}
		++i1;
		++i2;
	}
	return i1 == s1.size() && i2 == s2.size() ? true : false;
}
bool operator!=(const My_Str::string& s1, const My_Str::string& s2)
{
	return !(s1 == s2);
}

bool operator<=(const My_Str::string& s1, const My_Str::string& s2)
{
	return s1 < s2 || s1 == s2;
}
bool operator>(const My_Str::string& s1, const My_Str::string& s2)
{
	return !(s1 <= s2);
}


bool operator>=(const My_Str::string& s1, const My_Str::string& s2)
{
	return !(s1 < s2);
}

std::ostream& operator<<(std::ostream& out, const My_Str::string& s)
{
	for (int i = 0; i < s.size(); ++i)// Finite cycles , You can avoid strings containing '\0' The situation of 
	{	
		out << s[i];
	}
	//cout<<s.c_str();
	return out;
}

std::istream& operator >> (std::istream& in,  My_Str::string& s)
{
	char ch = 0;
	//ch = getchar();
	//while (ch != ' '&&ch!='\n')
	//{
	//	s += ch;
	//	ch = getchar();

	//}
	ch = in.get();
	while (ch != ' '&&ch!='\n')
	{
		s += ch;
		ch = in.get();
	}
	return in;
}

summary

Dealing with boundary problems , Be careful , Otherwise, the program may CREASH

原网站

版权声明
本文为[New Young]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/189/202207072258516396.html