C++ string类字符串的惯用操作及实现
C++ string类字符串的常用操作及实现

#include <stdlib.h> #include <string.h> namespace myspace { class string { public: //ctor 声明一个C++字符串 string(); string(const char* s); string(const char* s, size_t len); string(const string& rhs); string(size_t len, char ch); string(const string rhs, size_t begin, size_t len); // 重载操作符,复制赋值、比较、增长删除子串 string& operator=(const string& rhs); bool operator==(const string& rhs); bool operator>(const string& rhs); bool operator<(const string& rhs); bool operator!=(const string& rhs); string& operator+(const string& rhs); string& operator-(const string& rhs); // 删除子串,从begin开始的len长度被删除 string& erase(size_t begin = 0, size_t len = npos); // 查找在字符串中第一个与str中的某个字符匹配的字符 // 返回它的位置。搜索从index开始,如果没找到就返回string::npos size_t find_first_of(const basic_string &str, size_t index = 0); size_t find_first_of(const char *str, size_t index = 0); size_t find_first_of(const char *str, size_t index, size_t num); size_t find_first_of(char ch, size_t index = 0); // 在字符串中查找第一个与str中的字符都不匹配的字符 // 返回它的位置。搜索从index开始。如果没找到就返回string::nops size_t find_first_not_of( const string &str, size_t index = 0 ); size_t find_first_not_of( const char *str, size_t index = 0 ); size_t find_first_not_of( const char *str, size_t index, size_t num ); size_t find_first_not_of( char ch, size_t index = 0 ); // 在字符串中查找最后一个与str中的某个字符匹配的字符 // 返回它的位置。搜索从index开始。如果没找到就返回string::nops size_t find_last_of( const string &str, size_t index = npos ); size_t find_last_of( const char *str, size_t index = npos ); size_t find_last_of( const char *str, size_t index, size_t num ); size_t find_last_of( char ch, size_t index = npos ); // 在字符串中查找最后一个与str中的字符都不匹配的字符 // 返回它的位置。搜索从index开始。如果没找到就返回string::nops size_t find_last_not_of( const string &str, size_t index = npos ); size_t find_last_not_of( const char *str, size_t index = npos ); size_t find_last_not_of( const char *str, size_t index, size_t num ); size_t find_last_not_of( char ch, size_t index = npos ); //dtor ~string(); void copy( char *str, size_t num, size_t index ); //get size_t size() const; // from C++11, the data() is same with c_str() const char* data() const; const char* c_str() const; // set & get char* operator[](size_t index); private: char* data_; size_t len_; }; }
常用的C++string 函数,我自己实现的:
<span style="font-size:18px;"> </span><span style="font-size:14px;"> namespace myspace { // ctor 默认构造函数,生成长度为0的空字符串"\0" // 而不是生成'\0',有利于统一析构 string::string() : len_(0) { data_ = new char [1]; *data_ = '\0'; } // 复制构造C类字符串,并以'\0'结束 string::string( const char* s ) { if(NULL == s) { len_ = 0; data_ = new char [1]; *data_ = '\0'; } else { len_ = strlen(s); data_ = new char [len_ + 1]; strcpy( data_, s ); } } // 以一定长度(字符串长度和指定长度的最小值)复制构造C类字符串 // size_t会确保传入的长度len为非负数 string::string( const char* s, size_t len ) { if( NULL == s ) { len_ = 0; data_ = new char [1]; *data_ = '\0'; } else { len_ = (strlen(s) < len) ? strlen(s) : len; data_ = new char [len_ + 1]; strncpy( data_, s, len_ ); *(data_ + len_) = '\0'; } } // 复制构造同类型的string string::string( const string& rhs ) { len_ = rhs.size(); data_ = new char [len_ + 1]; strcpy( data_, rhs.c_str() ); } // 以len为长度的ch的拷贝(即有len个ch组成的string) // 注意:当ch=‘\0’时长度为0 string::string(size_t len, char ch) { len_ = (ch) ? len : 0; data_ = new char [len_ + 1]; for(int i=0; i<len_; ++i) { *(data_ + i) = ch; } *(data_ + len_) = '\0'; } // 以rhs的begin开始唱len的字符串初始化 string::string(const string rhs, size_t begin, size_t len) { len_ = len; data_ = new char [len_ + 1]; strncpy(data_, rhs.c_str() + begin, len); *(data_ + len_) = '\0'; } // copy assign // 改进,同时考虑到“自我赋值”和“异常”的安全性 string& string::operator=( const string& rhs ) { char *pOrig = data_; char *copy = new char [rhs.size() + 1]; strcpy( copy, rhs.c_str() ); data_ = copy; len_ = rhs.size(); delete [] pOrig; return *this; /* if( this != &rhs ) { delete [] data_; len_ = rhs.len_; data_ = new char [len_ + 1]; strcpy( data_, rhs.data_ ); } return *this; */ } // 只写一个其他类似 bool string::operator==(const string& rhs) { return !strcmp(this->c_str(), rhs.c_str()); } // 只写一个其他类似 string& string::operator+(const string& rhs) { size_t lenth = len_ + rhs.size() + 1; char *ptr = new char [lenth]; strcpy(ptr, data_); strcpy(ptr + len_, rhs.c_str()); delete [] data_; data_ = ptr; len_ = lenth; <span style="white-space:pre"> return *this;</span> } // 删除子串 string& string::erase(size_t begin, size_t len) { size_t lenth = len_ - len; char *ptr = new char [lenth]; strncpy(ptr, data_, begin); strcpy(ptr + begin, data_ + begin + len); delete [] data_; data_ = ptr; len_ = lenth; <span style="white-space:pre"> </span>return *this; } // dtor string::~string() { delete [] data_; } // 牺牲效率换取异常安全性 void string::copy(char *str, size_t len, size_t index) { char *orig = data_; char *ptr = new char [len + 1]; strncpy(ptr, str + index, len); *(ptr + len) = '\0'; data_ = ptr; delete [] orig; } size_t string::size() const { return len_; } // from C++11, the data() is same with c_str() const char* string::data() const { return c_str(); } const char* string::c_str() const { return data_; } char* string::operator[]( size_t index ) { return ( index > len_ ) ? NULL : data_ + index; } }</span>
经过测试,都OK~ 若有问题请提出以便修改;
<span style="font-size:14px;">#include <stdio.h> #include <assert.h> void test_string1() { // test string() qh::string str; assert( '\0' == *str[0] ); assert( 0 == str.size() ); assert( '\0' == *str.c_str() ); assert( '\0' == *str.data() ); // test copy assign str = qh::string(); assert( '\0' == *str[0] ); assert( 0 == str.size() ); assert( '\0' == *str.c_str() ); assert( '\0' == *str.data() ); // test string(cahr *) && copy assign str = qh::string( "jhsf" ); assert( 'j' == *str[0] ); assert( 4 == str.size() ); assert( 'j' == *str.c_str() ); assert( 'j' == *str.data() ); printf( "%s() all test OK!\n", __FUNCTION__ ); } void test_string2() { // test string(string& s) s="" qh::string s; qh::string str_test( s ); assert( '\0' == *str_test[0] ); assert( 0 == str_test.size() ); assert( '\0' == *str_test.c_str() ); assert( '\0' == *str_test.data() ); // test string(string&) const qh::string str_test2 = "abcdefgfgdgdfgfd"; qh::string str(str_test2); assert( 16 == str.size() ); assert( 'a' == *str.c_str() ); assert( 'a' == *str.data() ); assert( !strcmp(str.c_str(), str_test2.c_str()) ); // test operator[] assert( 'd' == *str[3] ); assert( 'f' == *str[7] ); assert( NULL == str[29] ); *str[7] = 'd'; assert( 'd' == *str[7] ); printf( "%s() all test OK!\n", __FUNCTION__ ); } void test_string3() { const char str_test[] = ""; // test string(char* s) s="" qh::string str(str_test); assert( '\0' == *str[0] ); assert( 0 == str.size() ); assert( '\0' == *str.c_str() ); assert( '\0' == *str.data() ); // test string(char* s, size_t) s="" qh::string str2(str_test, 4); // test operator[] assert( '\0' == *str2[0] ); assert( 0 == str2.size() ); assert( '\0' == *str2.c_str() ); assert( '\0' == *str2.data() ); printf( "%s() all test OK!\n", __FUNCTION__ ); } void test_string4() { // test string(char*, size_t) char str_test[] = "^%$^%$**&%*(^^#%"; qh::string str(str_test, 4); assert( '^' == *str.c_str() ); assert( '^' == *str.data() ); // test operator[] assert( '^' == *str[3] ); assert( NULL == str[29] ); assert( 4 == str.size() ); *str[2] = '^'; assert( '^' == *str[2] ); // test self copy assign qh::string str2 = "1234645765"; str2 = str2; assert(str2.c_str() != NULL); assert( '1' == *str2[0] ); assert( 10 == str2.size() ); assert( '1' == *str2.c_str() ); assert( '1' == *str2.data() ); printf("%s() all test OK!\n", __FUNCTION__); } int main(int argc, char* argv[]) { //TODO 在这里添加单元测试,越多越好,代码路径覆盖率越全越好 //TODO 单元测试写法请参考INIParser那个项目,不要写一堆printf,要用assert进行断言判断 test_string1(); test_string2(); test_string3(); test_string4(); #ifdef WIN32 system("pause"); #endif return 0; }</span>