C++ String部分成员怎么实现

发布时间:2022-08-29 16:56:16 作者:iii
来源:亿速云 阅读:108

C++ String部分成员怎么实现

引言

C++标准库中的std::string类是一个非常强大的工具,用于处理字符串。它提供了丰富的成员函数和操作符,使得字符串的处理变得简单而高效。本文将深入探讨std::string类中部分成员函数的实现原理,帮助读者更好地理解和使用这个类。

1. std::string的基本结构

在深入探讨成员函数的实现之前,我们先了解一下std::string的基本结构。std::string是一个模板类,定义在<string>头文件中。它的基本结构如下:

template<class CharT, class Traits = std::char_traits<CharT>, class Allocator = std::allocator<CharT>>
class basic_string {
    // 成员变量和成员函数
};

typedef basic_string<char> string;

std::string实际上是basic_string<char>的别名。basic_string模板类有三个模板参数:

2. std::string的构造函数

std::string提供了多个构造函数,用于从不同的数据源创建字符串对象。以下是几个常见的构造函数及其实现原理。

2.1 默认构造函数

默认构造函数创建一个空的字符串对象。

basic_string() noexcept(noexcept(Allocator())) : basic_string(Allocator()) {}

这个构造函数简单地调用了一个接受分配器参数的构造函数,传递了一个默认的分配器对象。

2.2 从C风格字符串构造

这个构造函数从C风格字符串(即以\0结尾的字符数组)创建一个std::string对象。

basic_string(const CharT* s, const Allocator& alloc = Allocator())
    : basic_string(s, Traits::length(s), alloc) {}

这个构造函数调用了另一个构造函数,传递了C风格字符串、字符串长度和分配器对象。Traits::length(s)用于计算C风格字符串的长度。

2.3 从字符数组构造

这个构造函数从字符数组创建一个std::string对象。

basic_string(const CharT* s, size_type count, const Allocator& alloc = Allocator())
    : alloc_(alloc) {
    data_ = alloc_.allocate(count + 1);
    Traits::copy(data_, s, count);
    data_[count] = CharT();
    size_ = count;
    capacity_ = count;
}

这个构造函数首先分配足够的内存来存储字符数组和终止符\0,然后使用Traits::copy将字符数组复制到分配的内存中,最后设置字符串的大小和容量。

3. std::string的析构函数

std::string的析构函数负责释放字符串对象占用的内存。

~basic_string() {
    if (data_) {
        alloc_.deallocate(data_, capacity_ + 1);
    }
}

析构函数首先检查data_指针是否为空,如果不为空,则调用分配器的deallocate函数释放内存。

4. std::string的赋值操作符

std::string提供了多个赋值操作符,用于从不同的数据源赋值给字符串对象。

4.1 从C风格字符串赋值

这个赋值操作符从C风格字符串赋值给std::string对象。

basic_string& operator=(const CharT* s) {
    return assign(s, Traits::length(s));
}

这个操作符调用了assign函数,传递了C风格字符串和字符串长度。

4.2 从字符数组赋值

这个赋值操作符从字符数组赋值给std::string对象。

basic_string& operator=(const CharT* s, size_type count) {
    return assign(s, count);
}

这个操作符调用了assign函数,传递了字符数组和字符数量。

5. std::stringassign函数

assign函数用于将字符串对象的内容替换为指定的内容。以下是几个常见的assign函数及其实现原理。

5.1 从C风格字符串赋值

basic_string& assign(const CharT* s, size_type count) {
    if (count > capacity_) {
        reserve(count);
    }
    Traits::copy(data_, s, count);
    data_[count] = CharT();
    size_ = count;
    return *this;
}

这个assign函数首先检查是否需要重新分配内存,然后使用Traits::copy将字符数组复制到字符串对象的内存中,最后设置字符串的大小。

5.2 从字符数组赋值

basic_string& assign(const CharT* s, size_type count) {
    if (count > capacity_) {
        reserve(count);
    }
    Traits::copy(data_, s, count);
    data_[count] = CharT();
    size_ = count;
    return *this;
}

这个assign函数的实现与上一个类似,只是参数类型不同。

6. std::stringappend函数

append函数用于在字符串的末尾追加内容。以下是几个常见的append函数及其实现原理。

6.1 追加C风格字符串

basic_string& append(const CharT* s, size_type count) {
    if (size_ + count > capacity_) {
        reserve(size_ + count);
    }
    Traits::copy(data_ + size_, s, count);
    size_ += count;
    data_[size_] = CharT();
    return *this;
}

这个append函数首先检查是否需要重新分配内存,然后使用Traits::copy将字符数组复制到字符串对象的末尾,最后更新字符串的大小。

6.2 追加字符数组

basic_string& append(const CharT* s, size_type count) {
    if (size_ + count > capacity_) {
        reserve(size_ + count);
    }
    Traits::copy(data_ + size_, s, count);
    size_ += count;
    data_[size_] = CharT();
    return *this;
}

这个append函数的实现与上一个类似,只是参数类型不同。

7. std::stringreserve函数

reserve函数用于预留足够的内存以存储指定数量的字符。

void reserve(size_type new_cap) {
    if (new_cap > capacity_) {
        CharT* new_data = alloc_.allocate(new_cap + 1);
        Traits::copy(new_data, data_, size_);
        new_data[size_] = CharT();
        if (data_) {
            alloc_.deallocate(data_, capacity_ + 1);
        }
        data_ = new_data;
        capacity_ = new_cap;
    }
}

这个reserve函数首先检查是否需要重新分配内存,然后分配新的内存,复制原有数据到新内存中,最后释放旧内存并更新容量。

8. std::stringresize函数

resize函数用于调整字符串的大小。

void resize(size_type count, CharT ch = CharT()) {
    if (count > size_) {
        if (count > capacity_) {
            reserve(count);
        }
        Traits::assign(data_ + size_, count - size_, ch);
        size_ = count;
        data_[size_] = CharT();
    } else if (count < size_) {
        size_ = count;
        data_[size_] = CharT();
    }
}

这个resize函数首先检查是否需要扩展或缩小字符串,然后根据需要分配内存或截断字符串,最后更新字符串的大小。

9. std::stringclear函数

clear函数用于清空字符串的内容。

void clear() noexcept {
    size_ = 0;
    data_[0] = CharT();
}

这个clear函数简单地将字符串的大小设置为0,并在字符串的开头放置一个终止符\0

10. std::stringempty函数

empty函数用于检查字符串是否为空。

bool empty() const noexcept {
    return size_ == 0;
}

这个empty函数简单地检查字符串的大小是否为0。

11. std::stringsizelength函数

sizelength函数用于获取字符串的大小。

size_type size() const noexcept {
    return size_;
}

size_type length() const noexcept {
    return size_;
}

这两个函数都返回字符串的大小。

12. std::stringcapacity函数

capacity函数用于获取字符串的容量。

size_type capacity() const noexcept {
    return capacity_;
}

这个函数返回字符串的容量。

13. std::stringc_str函数

c_str函数用于获取字符串的C风格表示。

const CharT* c_str() const noexcept {
    return data_;
}

这个函数返回字符串的内部字符数组指针。

14. std::stringdata函数

data函数用于获取字符串的字符数组指针。

const CharT* data() const noexcept {
    return data_;
}

这个函数返回字符串的内部字符数组指针。

15. std::stringoperator[]函数

operator[]函数用于访问字符串中的字符。

CharT& operator[](size_type pos) {
    return data_[pos];
}

const CharT& operator[](size_type pos) const {
    return data_[pos];
}

这个函数返回字符串中指定位置的字符引用。

16. std::stringat函数

at函数用于访问字符串中的字符,并进行边界检查。

CharT& at(size_type pos) {
    if (pos >= size_) {
        throw std::out_of_range("std::string::at");
    }
    return data_[pos];
}

const CharT& at(size_type pos) const {
    if (pos >= size_) {
        throw std::out_of_range("std::string::at");
    }
    return data_[pos];
}

这个函数在访问字符之前检查位置是否越界,如果越界则抛出std::out_of_range异常。

17. std::stringfrontback函数

frontback函数用于访问字符串的第一个和最后一个字符。

CharT& front() {
    return data_[0];
}

const CharT& front() const {
    return data_[0];
}

CharT& back() {
    return data_[size_ - 1];
}

const CharT& back() const {
    return data_[size_ - 1];
}

这两个函数分别返回字符串的第一个和最后一个字符的引用。

18. std::stringpush_back函数

push_back函数用于在字符串的末尾追加一个字符。

void push_back(CharT ch) {
    if (size_ == capacity_) {
        reserve(capacity_ * 2);
    }
    data_[size_] = ch;
    size_++;
    data_[size_] = CharT();
}

这个函数首先检查是否需要重新分配内存,然后在字符串的末尾追加字符,并更新字符串的大小。

19. std::stringpop_back函数

pop_back函数用于删除字符串的最后一个字符。

void pop_back() {
    if (size_ > 0) {
        size_--;
        data_[size_] = CharT();
    }
}

这个函数首先检查字符串是否为空,然后删除最后一个字符,并更新字符串的大小。

20. std::stringinsert函数

insert函数用于在字符串的指定位置插入内容。以下是几个常见的insert函数及其实现原理。

20.1 在指定位置插入字符

basic_string& insert(size_type index, size_type count, CharT ch) {
    if (index > size_) {
        throw std::out_of_range("std::string::insert");
    }
    if (size_ + count > capacity_) {
        reserve(size_ + count);
    }
    Traits::move(data_ + index + count, data_ + index, size_ - index);
    Traits::assign(data_ + index, count, ch);
    size_ += count;
    data_[size_] = CharT();
    return *this;
}

这个insert函数首先检查插入位置是否越界,然后检查是否需要重新分配内存,接着移动插入位置后的字符,最后插入指定数量的字符,并更新字符串的大小。

20.2 在指定位置插入C风格字符串

basic_string& insert(size_type index, const CharT* s, size_type count) {
    if (index > size_) {
        throw std::out_of_range("std::string::insert");
    }
    if (size_ + count > capacity_) {
        reserve(size_ + count);
    }
    Traits::move(data_ + index + count, data_ + index, size_ - index);
    Traits::copy(data_ + index, s, count);
    size_ += count;
    data_[size_] = CharT();
    return *this;
}

这个insert函数的实现与上一个类似,只是插入的内容是C风格字符串。

21. std::stringerase函数

erase函数用于删除字符串中的部分内容。以下是几个常见的erase函数及其实现原理。

21.1 删除指定位置的字符

basic_string& erase(size_type index = 0, size_type count = npos) {
    if (index > size_) {
        throw std::out_of_range("std::string::erase");
    }
    if (count == npos || index + count > size_) {
        count = size_ - index;
    }
    Traits::move(data_ + index, data_ + index + count, size_ - index - count);
    size_ -= count;
    data_[size_] = CharT();
    return *this;
}

这个erase函数首先检查删除位置是否越界,然后计算实际删除的字符数量,接着移动删除位置后的字符,最后更新字符串的大小。

21.2 删除指定位置的字符

iterator erase(const_iterator position) {
    size_type index = position - begin();
    erase(index, 1);
    return begin() + index;
}

这个erase函数首先计算删除位置的索引,然后调用上一个erase函数删除指定位置的字符,最后返回删除后的迭代器。

22. std::stringreplace函数

replace函数用于替换字符串中的部分内容。以下是几个常见的replace函数及其实现原理。

22.1 替换指定位置的字符

basic_string& replace(size_type pos, size_type count, const CharT* s, size_type count2) {
    if (pos > size_) {
        throw std::out_of_range("std::string::replace");
    }
    if (count == npos || pos + count > size_) {
        count = size_ - pos;
    }
    size_type new_size = size_ - count + count2;
    if (new_size > capacity_) {
        reserve(new_size);
    }
    Traits::move(data_ + pos + count2, data_ + pos + count, size_ - pos - count);
    Traits::copy(data_ + pos, s, count2);
    size_ = new_size;
    data_[size_] = CharT();
    return *this;
}

这个replace函数首先检查替换位置是否越界,然后计算实际替换的字符数量,接着移动替换位置后的字符,最后复制新的内容到替换位置,并更新字符串的大小。

22.2 替换指定位置的字符

basic_string& replace(size_type pos, size_type count, const CharT* s) {
    return replace(pos, count, s, Traits::length(s));
}

这个replace函数调用了上一个replace函数,传递了C风格字符串和字符串长度。

23. std::stringsubstr函数

substr函数用于获取字符串的子串。

basic_string substr(size_type pos = 0, size_type count = npos) const {
    if (pos > size_) {
        throw std::out_of_range("std::string::substr");
    }
    if (count == npos || pos + count > size_) {
        count = size_ - pos;
    }
    return basic_string(data_ + pos, count);
}

这个substr函数首先检查子串的起始位置是否越界,然后计算子串的长度,最后创建一个新的std::string对象并返回。

24. std::stringfind函数

find函数用于在字符串中查找子串或字符。以下是几个常见的find函数及其实现原理。

24.1 查找子串

size_type find(const CharT* s, size_type pos = 0) const {
    return find(s, pos, Traits::length(s));
}

size_type find(const CharT* s, size_type pos, size_type count) const {
    if (pos > size_) {
        return npos;
    }
    if (count == 0) {
        return pos;
    }
    for (size_type i = pos; i <= size_ - count; ++i) {
        if (Traits::compare(data_ + i, s, count) == 0) {
            return i;
        }
    }
    return npos;
}

这个find函数首先检查查找位置是否越界,然后遍历字符串,使用Traits::compare比较子串,如果找到匹配的子串则返回其位置,否则返回npos

24.2 查找字符

size_type find(CharT ch, size_type pos = 0) const {
    if (pos > size_) {
        return npos;
    }
    for (size_type i = pos; i < size_; ++i) {
        if (Traits::eq(data_[i], ch)) {
            return i;
        }
    }
    return npos;
}

这个find函数首先检查查找位置是否越界,然后遍历字符串,使用Traits::eq比较字符,如果找到匹配的字符则返回其位置,否则返回npos

25. std::stringrfind函数

rfind函数用于在字符串中从后向前查找子串或字符。以下是几个常见的

推荐阅读:
  1. C++实现CString和string的互相转换
  2. C++ 之新成员(八)

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

c++ string

上一篇:Java怎么利用深度优先和广度优先求解迷宫路径

下一篇:Spring中@Autowired和@Resource的区别是什么

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》