C++ string类(二)及深浅拷贝

一、string类方法使用举例

1.迭代器

迭代器本质:指针(理解)

迭代器:正向迭代器: begin() | end() 反向迭代器: rbegin() | rend()

2.find使用

//找到s中某个字符
void TestString3()
{
    string s("AAADEFNUIENFUIAAA");
    //找到AAA位置
    size_t pos = s.find("AAA");
    cout << pos << endl;
}

输出0,表示0位置处为AAA

3.获取文件后缀/substr

substr(pos = 0, n = npos);

从Pos位置开始,截取n个字符,如果n没有传递,表示从pos一直截取到末尾

如果都没有传递,截取整个字符

void TestString3()
{
    string s("124.text.cpp");
    //rfind从后面往前找 ’.’,+1找到后缀位置
    size_t pos =s.rfind('.') + 1;

    //从pos处截到末尾
    string postfix = s.substr(pos);
    cout << postfix << endl;
}

4.给多行单词,获取每行单词中最后一个单词的长度/getline

int main()
{
    string line;
    // 不要使用cin>>line,因为会它遇到空格就结束了
    // while(cin>>line)
    while (getline(cin, line))
    {
        size_t pos = line.rfind(' ');
        cout << line.size() - pos - 1 << endl;
    }
    return 0;
}

getline(cin,s): 获取一整行字符串,字符串中如果包含空格等空白字符也可以接收

oj练习

5.比大小

void Test()
{
    string s1("abc");
    string s2("afwef");
    if (s1 < s2)
    {
        cout << "s1<s2" << endl;
    }
    else if (s1>s2)
    {
        cout << "s1>s2" << endl;
    }
    else
    {
        cout << "s1=s2" << endl;
    }
}

6.其他一些练习OJ

反转字母OJ

找第一个出现的相同的字符

验证回文串

扫描二维码关注公众号,回复: 14862013 查看本文章

二. string类的模拟实现

1. 浅拷贝

浅拷贝:也称位拷贝,编译器只是将对象中的值拷贝过来。如果对象中管理资源,最后就会导致多个对象共享同一份资源,当一个对象销毁时就会将该资源释放掉,而此时另一些对象不知道该资源已经被释放,以为还有效,所以当继续对资源进项操作时,就会发生发生了访问违规

上述String类没有显式定义其拷贝构造函数与赋值运算符重载,此时编译器会合成默认的,当用s1构造s2时,编译器会调用默认的拷贝构造。最终导致的问题是,s1、s2共用同一块内存空间,在释放时同一块空间被释放多次而引起程序崩溃,这种拷贝方式,称为浅拷贝

2、解决浅拷贝的方法:深拷贝,写时拷贝(了解)

如果一个类中涉及到资源的管理,其拷贝构造函数、赋值运算符重载以及析构函数必须要显式给出。一般情况都是按照深拷贝方式提供

3.String类的模拟实现

正确实现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(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;
};

void TestString()
{
    String s1("hello");
    String s2(s1);
    String s3(s2);
}
int main()
{
    TestString();
    return 0;
}

如下,每个对象都有自己独立的空间,释放时也是,只释放自己的互不影响

深拷贝(现代版写法)

减少传统代码重复,相似性代码进行优化

class String
{
public:
     String(const char* str = "")
     {
        if (nullptr == str)
         {
             assert(false);
             return;
         }
         _str = new char[strlen(str) + 1];
         strcpy(_str, str);
     }
     String(const String& s)
         : _str(nullptr)//_Str可能为随机指针,要先置为空
     {
         String strTmp(s._str);
         swap(_str, strTmp._str);//交换地址
     }
    String& operator=(String s)//赋值运算符重载,先传入参数
     {
         swap(_str, s._str);//
         return *this;
     }

4.写时拷贝

写时拷贝就是一种拖延症,是在浅拷贝的基础之上增加了引用计数的方式来实现的。

引用计数:用来记录资源使用者的个数。在构造时,将资源的计数给成1,每增加一个对象使用该资源,就给计数增加1,当某个对象被销毁时,先给该计数减1,然后再检查是否需要释放资源,如果计数为1,说明该对象时资源的最后一个使用者,将该资源释放;否则就不能释放,因为还有其他对象在使用该资源

三、string模拟实现代码(全部)

#include <assert.h>
#include<iostream>
#include<string>
using namespace std;
namespace zx
{
    class string
    {
    public:
        typedef char* iterator;
        ///
        // 构造
        string(const char* str = "")
        {
            if (nullptr == str)
                str = "";

            _size = strlen(str);
            _capacity = _size;
            _str = new char[_capacity + 1];
            strcpy(_str, str);
        }

        string(const string& s)
        {
            string temp(s._str);
            this->swap(temp);
        }

        string(size_t n, char val)
        {
            _str = new char[n + 1];
            memset(_str, val, n);
            _str[n] = '\0';

            _size = n;
            _capacity = n;
        }

        string& operator=(string s)
        {
            this->swap(s);
            return *this;
        }

        ~string()
        {
            if (_str)
            {
                delete[] _str;
                _str = nullptr;
                _capacity = 0;
                _size = 0;
            }
        }

        /
        // 迭代器
        iterator begin()
        {
            return _str;
        }

        iterator end()
        {
            return _str + _size;
        }

        /
        // 容量
        size_t size()const
        {
            return _size;
        }

        size_t length()const
        {
            return _size;
        }

        size_t capacity()const
        {
            return _capacity;
        }

        bool empty()const
        {
            return 0 == _size;
        }

        void clear()
        {
            _size = 0;
        }

        void resize(size_t newsize, char val)
        {
            size_t oldsize = size();
            if (newsize > oldsize)
            {
                // 有效元素个数增多
                if (newsize > capacity())
                    reserve(newsize);

                // 多出的元素使用val填充
                memset(_str + _size, val, newsize - _size);
            }

            _size = newsize;
            _str[_size] = '\0';
        }

        void resize(size_t newsize)
        {
            resize(newsize, '\0');
        }

        void reserve(size_t newcapacity)
        {
            size_t oldcapacity = capacity();
            if (newcapacity > oldcapacity)
            {
                // 1. 申请新空间
                char* temp = new char[newcapacity + 1];

                // 2. 拷贝元素
                strncpy(temp, _str, _size);

                // 3. 释放旧空间
                delete[] _str;

                // 4. 使用新空间
                _str = temp;

                _capacity = newcapacity;
                _str[_size] = '\0';
            }
        }

        
        // 元素访问
        char& operator[](size_t index)
        {
            assert(index < _size);
            return _str[index];
        }

        const char& operator[](size_t index)const
        {
            assert(index < _size);
            return _str[index];
        }

        char& at(size_t index)
        {
            // 如果越界,抛出out_of_range的异常
            return _str[index];
        }

        const char& at(size_t index)const
        {
            // 如果越界,抛出out_of_range的异常
            return _str[index];
        }

        //
        // modify
        void push_back(char ch)
        {
            *this += ch;
        }

        string& operator+=(char ch)
        {
            if (_size == _capacity)
                reserve((size_t)_capacity*1.5 + 3);

            _str[_size] = ch;
            ++_size;
            _str[_size] = '\0';
            return *this;
        }

        string& operator+=(const char* str)
        {
            size_t needSpace = strlen(str);
            size_t leftSpace = capacity() - size();
            if (needSpace > leftSpace)
            {
                reserve(capacity()+ needSpace);
            }

            strcat(_str, str);
            _size += needSpace;
            _str[_size] = '\0';

            return *this;
        }

        string& operator+=(const string& s)
        {
            *this += s.c_str();
            return *this;
        }

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

        string& appent(const string& s)
        {
            *this += s;
            return *this;
        }

        string& insert(size_t pos, const string& s);
        string& erase(size_t pos = 0, size_t n = npos);

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

        
        const char* c_str()const
        {
            return _str;
        }

        size_t find(char ch, size_t pos = 0)const
        {
            if (pos >= _size)
            {
                return npos;
            }

            for (size_t i = pos; i < _size; ++i)
            {
                if (_str[i] == ch)
                    return i;
            }

            return npos;
        }

        size_t rfind(char c, size_t pos = npos)
        {
            if (pos >= _size)
            {
                pos = _size-1;
            }

            for (int i = pos; i >= 0; --i)
            {
                if (_str[i] == c)
                    return i;
            }

            return npos;
        }

        string substr(size_t pos = 0, size_t n = npos) const
        {
            // 从pos位置开始,往后借助n个字符长度
            if (pos >= _size)
            {
                return string();
            }

            // 从pos到字符串的末尾剩余字符个数
            n = min(n, _size - pos);

            string temp(n, '\0');
            size_t index = 0;
            for (size_t i = pos; i < pos+n; ++i)
            {
                temp[index++] = _str[i];
            }

            return temp;
        }

    private:
        char* _str;
        size_t _size;
        size_t _capacity;

        const static size_t npos = -1;

        friend ostream& operator<<(ostream& out, const string& s);
    };

    ostream& operator<<(ostream& out, const string& s)
    {
        for (size_t i = 0; i < s.size(); ++i)
        {
            cout << s[i];
        }

        return out;
    }
}

int main()
{
    // TestMyString01();
    // TestMyString02();

    // TestMyString03();
    TestMyString04();
    _CrtDumpMemoryLeaks();
    return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_59215611/article/details/129224688