C++17的 std::string_view 是为了解决什么问题?它和 const std::string& 相比有什么核心优势和潜在陷阱?

C++17的 std::string_view 是为了解决什么问题?它和 const std::string& 相比有什么核心优势和潜在陷阱?

const std::string& 的隐式开销

在C++17之前,编写一个接收只读字符串的函数,最常用的方式是使用const std::string&

c++ 复制代码
void print_string(const std::string& str) {
    std::cout << str << std::endl;
}

当传入 std::stringprint_string(my_std_string);

  1. 没有拷贝,只有一个引用传递,开销极小

当传入字符串字面量或C风格字符串时print_string("hello, world");

  1. 这里有效率问题! "hello, world" 的类型是 const char*,与函数期望的 std::string 不匹配
  2. 为了让调用成功,编译器会创建一个临时的 std::string 对象
    1. 一次堆内存分配 (Heap Allocation) 来存放字符串内容
    2. 一次内存拷贝,将字面量的内容拷贝到新分配的内存中
  3. 函数调用结束后,这个临时对象被销毁,内存被释放。在性能敏感的代码或循环中,这种开销是完全不必要的

std::string_view 的核心优势

std::string_view 是一个非所有权的轻量级对象,它本身不存储任何字符串数据,仅仅持有两样东西:

  1. 一个指向字符序列起始位置的指针
  2. 字符序列的长度

像一个"窗口",可以"俯瞰"一块已经存在的内存,但从不负责管理这块内存的生命周期

使用 std::string_view 改造函数:

c++ 复制代码
void print_string_view(std::string_view sv) { // sv现在是一个视图
    std::cout << sv << std::endl;
}

当传入 std::stringprint_string_view(my_std_string);

  1. 开销极小。std::string_view 被创建,其内部指针指向 my_std_string 的内部缓冲区,并记录其长度。没有内存分配

当传入字符串字面量时print_string_view("hello, world");

  1. 开销极小。std::string_view 被创建,其内部指针直接指向程序静态存储区的字符串字面量,并记录其长度。没有内存分配,没有拷贝

处理子字符串时优势更明显

c++ 复制代码
std::string big_string = "this-is-a-long-string";
// 使用std::string创建子串,有一次新的内存分配和拷贝
std::string sub = big_string.substr(5, 4); 

// 使用std::string_view创建子串,零开销!
// 仅仅是移动了指针并改变了长度记录
std::string_view sv_sub = std::string_view(big_string).substr(5, 4);

潜在陷阱:悬垂视图 (Dangling Views)

因为std::string_view不拥有数据,如果它指向的原始数据被销毁了,string_view 就会变成一个悬垂视图 ,指向一块无效的内存。此时使用它将导致未定义行为 (Undefined Behavior)

c++ 复制代码
#include <string>
#include <string_view>
#include <iostream>

std::string_view get_a_dangling_view() {
    std::string temp_str = "This string is temporary";
    return temp_str; // 危险!返回了一个视图,它指向即将被销毁的temp_str
} // temp_str 在这里被销毁,其内存被释放

int main() {
    std::string_view sv = get_a_dangling_view();
    
    // 此刻 sv 已经是一个悬垂视图
    std::cout << sv << std::endl; // 未定义行为!可能会打印垃圾信息,或导致程序崩溃
}

sv 指向的内存在get_a_dangling_view函数返回时就已经失效

使用准则

何时使用?

  1. 函数参数std::string_view 最理想、最安全的使用场景。因为函数调用期间,传入的原始字符串(无论是std::string还是字面量)的生命周期都有效

何时要警惕?

  1. 不要std::string_view作为函数的返回值,除非你能确保它指向的数据(例如一个全局常量或程序生命周期内的对象)不会失效
  2. std::string_view作为类成员时要格外小心,必须确保其指向的数据源对象的生命周期比持有视图的这个类实例更长
相关推荐
澄澈i35 分钟前
设计模式学习[17]---组合模式
c++·学习·设计模式·组合模式
1白天的黑夜11 小时前
前缀和-1314.矩阵区域和-力扣(LeetCode)
c++·leetcode·前缀和
jdlxx_dongfangxing2 小时前
2023 年 NOI 最后一题题解
c++·noi
Q741_1472 小时前
优选算法 力扣 202.快乐数 快慢双指针 解决带环问题 C++解题思路 每日一题
c++·算法·leetcode·快慢双指针·环形问题
R-G-B2 小时前
【C++ 初级工程师面试--4】形参带默认值的函数,特点,效率,注意事项
开发语言·c++·形参带默认值的函数·形参默认值特点,效率,注意事项·形参默认值特点·形参默认值效率·形参默认值注意事项
YLCHUP3 小时前
题解:P4447 [AHOI2018初中组] 分组
开发语言·数据结构·c++·经验分享·算法·贪心算法·抽象代数
R-G-B3 小时前
【10】大恒相机SDK C++开发 ——对相机采集的原图像数据IFrameData裁剪ROI 实时显示在pictureBox中,3种方法实现(效率不同)
c++·大恒相机开发·大恒相机·工业相机原图像数据裁剪roi·iframedata裁剪roi·原图像数据裁剪roi 实时显示
三小尛4 小时前
C++友元
开发语言·c++·算法
小指纹4 小时前
河南萌新联赛2025第(三)场:河南理工大学【补题】
数据结构·c++·算法·macos·ios·objective-c·cocoa