string模拟实现:(二)

简介: 2.string类常用接口的实现:size()和capacity()size_t size()const

2.string类常用接口的实现:

size()和capacity()

size_t size()const
{
  return  _size;
}
size_t capacity()const
{
  return  _capacity;
}

clear函数

对于 clear() 而言就是去清除当前对象的数据,我们直接在_str[0]这个位置放上一个\0即可,并且再去修改一下它的_size = 0即可

  • 不过这个接口来说我们不要去加【const成员】,因为修改了其成员变量_size
void clear()
{
  _str[0] = '\0';
  _size = 0;
}

c_str函数

返回一个指向数组的指针,该数组包含一个以空字符结尾的字符序列(即C-string),表示string对象的当前值。

这个数组包含的字符序列与string对象的值相同,另外还包含一个以空字符(‘\0’)结尾的字符串。

  • 🔥c_str返回的是一个const char*的数组指针,只读不写
const char* c_str()const
{
  return _str;
}

❓调试到这个地方就直接崩了,不应该直接打印null吗?

image-20230601110201130如果我们换成std中的string,不会报错,说明我们初始化存在问题

namespace st
{
  class string
  {
  public:
    string()
      :_str(nullptr)
      , _size(0)
      , _capacity(0)
    {}
    string(const char* str)
      :_str(str)
      , _size(strlen(str))
      , _capacity(strlen(str))
    {}
    const char* c_str()
    {
      return _str;
    }
  private:
    const char* _str;
    size_t _size;
    size_t _capacity;
  };
  void test_string1()
  {
    string s1;
    string s2("hello world");
    std::cout << s1.c_str() << std::endl;
    std::cout << s2.c_str() << std::endl;
  }
}
int main()
{
  st::test_string1();
  return 0;
}

2.1全缺省构造函数

我们还要考虑不带参数的构造函数,如下:

void test_string1() {
  string s1("hello world");    // 带参
  string s2;                   // 不带参
}
string(const char* str = "")
      :_size(strlen(str))
    {
      _capacity = _size == 0 ? 3 : _size;
      _str = new char[_capacity + 1];
      strcpy(_str, str);
    }


🔥这里值得注意的是缺省值,我们给了一个“”

🔑详细解析:

str是一个char*类型,正常情况下,我们会给缺省值为nullptr

string(const char* str = nullptr)

这里运行后会崩!!!

strlen是不会去检查空的,它是一直找到 \0为止的

也就相当于直接对这个字符串进行解引用了,这里的字符串又是空,所以会引发空指针问题。

所以我们这里给的是一个空的字符串 " ",常量字符串默认就带有 \0,这样就不会出问题:

string(const char* str = "")

❓为什么我们用new char[1]而不是直接用new char,都是一个啊为什么啊?

🔥为了跟有参构造那里匹配析构函数,这样就方便释放

string()
      :_str(new char[1])
      , _size(0)
      , _capacity(0)
    {
      _str[0] = '\0';
    }
    string(const char* str)
      :_size(strlen(str))
    {
      _capacity = _size;
      _str = new char[_capacity + 1];
      strcpy(_str, str);
    }

❓这里可以优化吗?

string(const char*str=nullptr)
string(const char* str = '\0')

🔑详细解析:

这两个都不可以,不可以解引用空指针

string(const char* str = "\0")

这样是可以的,给常量字符串,但是没必要这样,可以下面这样

string(const char* str = "")

如果我们不写拷贝构造函数,默认生成了一个拷贝构造函数,会报错!

void test_string2()
  {
    string s1;
    string s2("hello world");
    string s3(s2);
    std::cout << s1.c_str() << std::endl;
    std::cout << s2.c_str() << std::endl;
    std::cout << s3.c_str() << std::endl;
  }

这里发生浅拷贝,同一块空间会被释放两次

string(const string& str)
      :_size(str._size)
      ,_capacity(str._capacity)
    {
      _str = new char[str._capacity+ 1];
      strcpy(_str, str._str);
    }

2.2拷贝构造函数

2.3operator[]的实现

❓[]重定向,这里有什么问题呢?

char& operator[](size_t pos)
    {
      assert(pos < _size);
      return _str[pos];
    }
//成员变量
private:
    const char* _str;
    size_t _size;
    size_t _capacity;

普通对象可以调用,但是 const 对象呢?所以我们还要考虑一下 const 对象。

我们可能会修改pos位置的字符,也可能加字符,这里会报错,因为str为const char*类型

const char& operator[](size_t pos)const
    {
      assert(pos < _size);
      return _str[pos];
    }
    char& operator[](size_t pos)//构成函数重载
    {
      assert(pos < _size);
      return _str[pos];
    }

2.4operator=的实现及其必要性

赋值的话,不写拷贝构造的话也是值拷贝(浅拷贝)

s1 = s3;下图拷贝构造分为三种:

第一种:s1的空间和s3的空间一样大

第二种:s1的空间比s3的空间大

第三种:s1的空间比s3的空间小

显然:这里第三种情况内存不够,要先释放防止内存泄漏,第二种是内存浪费,干脆全部都重新开空间就好了

string& operator=(const string& str)
    {
      if (&str == this)
        return *this;//防止自己给自己赋值
      char*tmp = new char[str._capacity + 1];//防止开辟失败
      strcpy(tmp, str._str);
      delete[] this->_str;
      _str = tmp;
      _size = str._size;
      _capacity = str._capacity;
      return *this;
    }



2.5Print函数

这里权限放大了

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

const函数,修饰this指针,但是这样另外一个地方又报错了

构成函数重载就可以解决问题了,各调用各的,这里调用第二个就可以了,this没有const修饰,并且返回类型没有const,就可以进行++等修改操作了

const char& operator[](size_t pos)const
    {
      assert(pos < _size);
      return _str[pos];
    }
      char& operator[](size_t pos)//构成函数重载
    {
      assert(pos < _size);
      return _str[pos];
    }
相关文章
|
存储 C语言 C++
string的使用和模拟实现-1
string的使用和模拟实现
|
2月前
|
C++ 容器
|
2月前
|
C++ 容器
|
2月前
|
C++
|
5月前
|
编译器 程序员 C语言
【C++】string模拟实现
这篇博客探讨了自定义实现C++ `string` 类的关键功能,包括构造、拷贝构造、赋值运算符重载及析构函数。作者强调了理解并实现这些功能对于面试的重要性。博客介绍了`string` 类的头文件`string.h`,其中定义了迭代器、基本成员函数如`swap()`、`size()`、`c_str()`等,并提到了深拷贝概念。此外,还展示了构造函数、析构函数和赋值运算符的实现,以及迭代器的定义与使用。博客还包括对C语言字符串函数的引用,以辅助读者理解实现细节。
|
6月前
|
C语言 C++
【c++】string模拟实现(2)
【c++】string模拟实现(2)
26 0
|
6月前
|
算法 C++
【c++】string模拟实现(1)
【c++】string模拟实现(1)
135 0
|
6月前
string的模拟实现
string的模拟实现
29 0
|
7月前
|
存储 C++
C++:String的模拟实现
C++:String的模拟实现
|
7月前
|
编译器 C++
【C++】模拟实现string
【C++】模拟实现string