C++笔记:std::string_view

std::string_view 是 C++17 引入的 轻量级字符串"只读视图"

它不拥有字符串,只是"指向一段连续字符"的 (ptr, length) 二元组。

核心目的:

避免创建临时 std::string、减少拷贝,提高性能。

cpp 复制代码
void f(std::string_view s);

你可以传:

  • std::string

  • const char*

  • 字面量 "hello"

  • char[]

并且不用分配内存、不拷贝内容

内部原理

如果你去翻源码(我这里放MSVC的实现源码),你会发现它的关键点就在这两个成员变量里

cpp 复制代码
using string_view = basic_string_view<char>;

template <class _Elem, class _Traits>
class basic_string_view {
public:
    using const_pointer          = const _Elem*;
    using size_type              = size_t;
private:
    const_pointer _Mydata;
    size_type _Mysize;
};

说人话就是

cpp 复制代码
class string_view {
    const char* data_;   // 指向外部的字符串内容
    size_t size_;        // 长度
};
  • 没有 '\0' 终止符的要求

  • 没有内存所有权

  • 不会自动管理被观察数据的生命周期

它仅仅是一个"窗口",与实际的存储分离。(不知道读者是否用过pytorch,这就很像Tensor里storage和view的关系)

所以:

cpp 复制代码
std::string_view sv = some_string.substr(...);  // OK,zero-copy

但是:

cpp 复制代码
std::string_view sv;
{
    std::string s = "abc";
    sv = s;     // sv 指向 s 的内部 storage
}              // s 析构 → sv 悬空

==> 悬空引用

string_view 的主要 API

构造函数

cpp 复制代码
constexpr string_view() noexcept;//空视图,data=nullptr, size=0。
constexpr string_view(const char* s);//空视图,data=nullptr, size=0。
constexpr string_view(const char* s, size_t count);//从指针 + 长度构造,不需要 '\0'。
constexpr string_view(const std::string& str) noexcept;//引用 str.data(),str.size()。

数据访问

cpp 复制代码
constexpr const char* data() const noexcept;
constexpr size_t size() const noexcept;
constexpr bool empty() const noexcept;
constexpr const char& operator[](size_t pos) const;
constexpr const char& at(size_t pos) const;
constexpr const char& front() const;
constexpr const char& back() const;
//还有begin,end等等迭代器,和string一样

字符串操作

cpp 复制代码
//不分配,不复制,仍然只是 view。
constexpr string_view substr(size_t pos = 0, size_t count = npos) const;
//负 → 小,正 → 大。
constexpr int compare(string_view sv) const noexcept;

//find 系列
size_t find(string_view sv, size_t pos = 0) const noexcept;
size_t find(char c, size_t pos = 0) const noexcept;
size_t rfind(...);
size_t find_first_of(...);
size_t find_last_of(...);
size_t find_first_not_of(...);
size_t find_last_not_of(...);

修改 view 本身

不改变底层字符,只是移动窗口。

cpp 复制代码
constexpr void remove_prefix(size_t n);
constexpr void remove_suffix(size_t n);

例子:

cpp 复制代码
std::string_view sv = "hello";
sv.remove_prefix(1);  // "ello"
sv.remove_suffix(2);  // "el"

转换回 string

cpp 复制代码
std::string s = std::string(view); // 复制!

这会真的 copy 内容。

string_view 使用注意事项

悬空引用

cpp 复制代码
std::string_view sv;
{
    std::string tmp = "abc";
    sv = tmp;  // 指向 tmp.data()
}              // tmp销毁 → sv悬空

指向临时字符串也有问题

cpp 复制代码
std::string_view sv = std::string("abc"); // 临时对象立即销毁

指向 vector<char> resize 后失效

底层存储可能重新分配。

不保证 null-terminated

你不能把 string_view.data() 当 C 字符串用。

cpp 复制代码
printf("%s", sv.data()); // 如果现在不是 '\0' 结尾 → UB

与const string &的区别

其实看到api也大概能感受到了,string_view作为窗口,仅仅起到观察的效果,不拥有资源。并且这个窗口本身也是可以进行修改的。

所以如果仅仅是一次性的引用string,那么这两者几乎没区别

但是如果使用时需要调整,比如需要取substr,如果使用const string&,就会额外拷贝一个string出来。但是如果使用string_view,那么仅仅是新开一个窗口观察,开销更小。

当然,由于string_view是只读的,如果需要修改字符串,还是需要string&的

相关推荐
草莓熊Lotso17 小时前
C++11 核心特性实战:列表初始化 + 右值引用与移动语义(附完整代码)
java·服务器·开发语言·汇编·c++·人工智能·经验分享
初夏睡觉18 小时前
从0开始c++,但是重置版,第1篇(c++基本框架)
开发语言·c++
老王熬夜敲代码18 小时前
进程PCB
linux·笔记
草莓熊Lotso18 小时前
GCC/G++ 编译器完全指南:从编译流程到进阶用法(附实操案例)
linux·运维·服务器·网络·c++·人工智能·自动化
HainesFreeman19 小时前
dns server是什么?自建的dns server是什么东西?有啥用?
笔记
xian_wwq1 天前
【学习笔记】攻击链贯穿端边云!边缘网络访问三大核心风险预警
笔记·学习·安全·边缘计算
workflower1 天前
时序数据获取事件
开发语言·人工智能·python·深度学习·机器学习·结对编程
CoderYanger1 天前
C.滑动窗口-求子数组个数-越长越合法——2799. 统计完全子数组的数目
java·c语言·开发语言·数据结构·算法·leetcode·职场和发展
C++业余爱好者1 天前
Java 提供了8种基本数据类型及封装类型介绍
java·开发语言·python
林杜雨都1 天前
Action和Func
开发语言·c#