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&的

相关推荐
zh_xuan2 分钟前
libcurl调用https接口
c++·libcurl
就叫飞六吧3 分钟前
QT写一个桌面程序exe并动态打包基本流程(c++)
开发语言·c++
蜡笔小马5 分钟前
1.c++设计模式-工厂模式
c++
threelab13 分钟前
Three.js 代码云效果 | 三维可视化 / AI 提示词
开发语言·javascript·人工智能
V搜xhliang024621 分钟前
OpenClaw科研全场景用法:从文献到实验室的完整自动化方案
运维·开发语言·人工智能·python·算法·microsoft·自动化
05候补工程师23 分钟前
【ROS 2 具身智能】Gazebo 仿真避坑指南:从“幽灵机器人”到传感器数据流打通
人工智能·经验分享·笔记·ubuntu·机器人
kaikaile199528 分钟前
风、浪、流环境模型的船舶三自由度(纵荡、横荡、艏摇)运动仿真MATLAB
开发语言·人工智能·matlab
chushiyunen28 分钟前
pandas使用笔记、数据清洗、json_normalize
笔记·pandas
fish_xk29 分钟前
map和set
java·开发语言
HERR_QQ29 分钟前
端到端课程自用 4 规划 基于自规划AR的端到端规划 AI 笔记
人工智能·笔记·自动驾驶·transformer