stringクラス、stringクラスシミュレーション実装、深浅コピー、写実コピー
1.なぜstringクラスを学ぶのですか?
C言語では、文字列は'0'で終わる文字の集合であり、操作を容易にするために、C標準ライブラリにはstrシリーズのライブラリ関数がいくつか提供されていますが、これらのライブラリ関数は文字列とは分離されており、OOPの考えにはあまり合っていません.また、下位空間にはユーザー自身の管理が必要で、うっかりすると境界を越えてアクセスする可能性があります.
2.標準ライブラリのstringクラス
2.1 stringクラス
1.stringは文字列を表す文字列クラス
2.このクラスのインタフェースは、通常のコンテナのインタフェースと基本的に同じであり、stringを操作するための通常の操作を追加した.
3.stringの下位レベルでの実績:basic_stringテンプレートクラスの別名、typedef basic_string string;
4.マルチバイトまたは長い文字のシーケンスを操作できません.
stringクラスを使用する場合は、ヘッダファイルとusing namespace stdを含める必要があります.
2.2 stringクラスの共通インタフェースの説明
詳細は本人のブログコレクションを参照してください.またはアドレスhttps://blog.csdn.net/tx_812214/article/details/89266591
3.stringクラスのシミュレーション実装
3.1古典的string類問題
説明:上記Stringクラスでは、コピーコンストラクション関数と付与演算子の再ロードが明示的に定義されていません.コンパイラはデフォルトを合成し、s 1でs 2を構築すると、コンパイラはデフォルトのコピーコンストラクションを呼び出します.最終的に、s 1、s 2は同じメモリ空間を共有し、解放時に同じ空間が複数回解放されてプログラムがクラッシュするコピー方式を、浅いコピーと呼ぶ.
3.2浅いコピー
浅いコピー:ビットコピーとも呼ばれ、コンパイラはオブジェクトの値をコピーするだけです.オブジェクトでリソースを管理すると、最後に複数のオブジェクトが同じリソースを共有し、1つのオブジェクトが破棄されるとリソースが解放されますが、他のオブジェクトはリソースが解放されたことを知らず、有効だと思っていたため、リソースのエントリ操作を続行するとアクセス違反が発生します.浅いコピーの問題を解決するには、C++に深いコピーが導入されています.
3.3深いコピー
クラスにリソースの管理が含まれている場合は、コピーコンストラクション関数、付与演算子の再ロード、およびコンストラクション関数を明示的に指定する必要があります.一般的には、深いコピー方式で提供されます.
3.3.1伝統版表記のString類
3.3.2現代版表記のString類
3.3書き込み時コピー
参照数:リソース・コンシューマの数を記録します.構築時、リソースのカウントを1にし、1つのオブジェクトを追加するたびにリソースを使用し、カウントを1にし、あるオブジェクトが破棄された場合、まずそのカウントを1に減らしてから、リソースを解放する必要があるかどうかを確認し、カウントが1であれば、そのオブジェクトを説明する際のリソースの最後の使用者は、リソースを解放する.他のオブジェクトがリソースを使用しているため、解放できません.
3.4 stringクラスのシミュレーション実装
C言語では、文字列は'0'で終わる文字の集合であり、操作を容易にするために、C標準ライブラリにはstrシリーズのライブラリ関数がいくつか提供されていますが、これらのライブラリ関数は文字列とは分離されており、OOPの考えにはあまり合っていません.また、下位空間にはユーザー自身の管理が必要で、うっかりすると境界を越えてアクセスする可能性があります.
2.標準ライブラリのstringクラス
2.1 stringクラス
1.stringは文字列を表す文字列クラス
2.このクラスのインタフェースは、通常のコンテナのインタフェースと基本的に同じであり、stringを操作するための通常の操作を追加した.
3.stringの下位レベルでの実績:basic_stringテンプレートクラスの別名、typedef basic_string string;
4.マルチバイトまたは長い文字のシーケンスを操作できません.
stringクラスを使用する場合は、ヘッダファイルとusing namespace stdを含める必要があります.
2.2 stringクラスの共通インタフェースの説明
詳細は本人のブログコレクションを参照してください.またはアドレスhttps://blog.csdn.net/tx_812214/article/details/89266591
3.stringクラスのシミュレーション実装
3.1古典的string類問題
class String
{
public:
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 s2(s1);
}
説明:上記Stringクラスでは、コピーコンストラクション関数と付与演算子の再ロードが明示的に定義されていません.コンパイラはデフォルトを合成し、s 1でs 2を構築すると、コンパイラはデフォルトのコピーコンストラクションを呼び出します.最終的に、s 1、s 2は同じメモリ空間を共有し、解放時に同じ空間が複数回解放されてプログラムがクラッシュするコピー方式を、浅いコピーと呼ぶ.
3.2浅いコピー
浅いコピー:ビットコピーとも呼ばれ、コンパイラはオブジェクトの値をコピーするだけです.オブジェクトでリソースを管理すると、最後に複数のオブジェクトが同じリソースを共有し、1つのオブジェクトが破棄されるとリソースが解放されますが、他のオブジェクトはリソースが解放されたことを知らず、有効だと思っていたため、リソースのエントリ操作を続行するとアクセス違反が発生します.浅いコピーの問題を解決するには、C++に深いコピーが導入されています.
3.3深いコピー
クラスにリソースの管理が含まれている場合は、コピーコンストラクション関数、付与演算子の再ロード、およびコンストラクション関数を明示的に指定する必要があります.一般的には、深いコピー方式で提供されます.
3.3.1伝統版表記のString類
class String
{
public:
String(const char* str = "")
{
// string , nullptr , ,
if(nullptr == str)
{
assert(false);
return;
}
_str = new char[strlen(str) + 1];
strcpy(_str, str);
}
String(const String& s)
: _str(new char[strlen(s._str)+1])
{
strcpy(_str, s._str);
}
String& operator=(const String& s)
{
if(this != &s)
{
char* pStr = new char[strlen(s._str) + 1];
strcpy(pStr, s._str);
delete[] _str;
_str = pStr;
}
return *this;
}
~String()
{
if(_str)
{
delete[] _str;
_str = nullptr;
}
}
private:
char* _str;
};
3.3.2現代版表記の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);
}
// ?
String& operator=(String s)
{
swap(_str, s._str);
return *this;
}
/*
String& operator=(const String& s)
{
if(this != &s)
{
String strTmp(s);
swap(_str, strTmp._str);
}
return *this;
}
*/
~String()
{
if(_str)
{
delete[] _str;
_str = nullptr;
}
}
private:
char* _str;
};
3.3書き込み時コピー
参照数:リソース・コンシューマの数を記録します.構築時、リソースのカウントを1にし、1つのオブジェクトを追加するたびにリソースを使用し、カウントを1にし、あるオブジェクトが破棄された場合、まずそのカウントを1に減らしてから、リソースを解放する必要があるかどうかを確認し、カウントが1であれば、そのオブジェクトを説明する際のリソースの最後の使用者は、リソースを解放する.他のオブジェクトがリソースを使用しているため、解放できません.
3.4 stringクラスのシミュレーション実装
namespace bit
{
class String
{
public:
typedef char* Iterator;
public:
String(const char* str = "")
{
// string , nullptr , ,
if (nullptr == str)
{
assert(false);
return;
}
_size = strlen(str);
_capacity = _size;
_str = new char[_capacity+1];
strcpy(_str, str);
}
String(const String& s)
: _str(new char[s._capacity + 1])
, _size(s._size)
, _capacity(s._capacity)
{
strcpy(_str, s._str);
}
String& operator=(const String& s)
{
if (this != &s)
{
char* pStr = new char[s._capacity + 1];
strcpy(pStr, s._str);
delete[] _str;
_str = pStr;
_size = s._size;
_capacity = s._capacity;
}
return *this;
}
~String()
{
if (_str)
{
delete[] _str;
_str = nullptr;
}
}
Iterator Begin()
{
return _str;
}
Iterator End()
{
return _str + _size;
}
void PushBack(char c)
{
if (_size == _capacity)
Reserve(_capacity*2);
_str[_size++] = c;
_str[_size] = '\0';
}
void Append(size_t n, char c)
{
for (size_t i = 0; i < n; ++i)
PushBack(c);
}
String& operator+=(char c)
{
PushBack(c);
return *this;
}
void Clear()
{
_size = 0;
_str[_size] = '\0';
}
void Swap(String& s)
{
swap(_str, s._str);
swap(_size, s._size);
swap(_capacity, s._capacity);
}
const char* C_Str()const
{
return _str;
}
/////////////////////////////////////////////////////////////////
// capacity
size_t Size()const
{
return _size;
}
size_t Capacity()const
{
return _capacity;
}
bool Empty()const
{
return 0 == _size;
}
void Resize(size_t newSize, char c = char())
{
if (newSize > _size)
{
// newSize ,
if (newSize > _capacity)
{
Reserve(newSize);
}
memset(_str + _size, c, newSize - _size);
}
_size = newSize;
_str[newSize] = '\0';
}
void Reserve(size_t newCapacity)
{
// ,
if (newCapacity > _capacity)
{
char* str = new char[newCapacity + 1];
strcpy(str, _str);
// ,
delete[] _str;
_str = str;
_capacity = newCapacity;
}
}
////////////////////////////////////////////////////////////////////
// access
char& operator[](size_t index)
{
assert(index < _size);
return _str[index];
}
const char& operator[](size_t index)const
{
assert(index < _size);
return _str[index];
}
size_t Find (char c, size_t pos = 0) const;
// s string
size_t Find (const char* s, size_t pos = 0) const;
// string pos n
String SubStr(size_t pos, size_t n);
// pos c/ str,
String& Insert(size_t pos, char c);
String& Insert(size_t pos, const char* str);
// pos ,
String& Erase(size_t pos, size_t len);
private:
friend ostream& operator<