Tip of the Week #1: string_view

C-C++基础与进阶 同时被 2 个专栏收录
70 篇文章 2 订阅
14 篇文章 6 订阅

Tip of the Week #1: string_view

Originally published as totw/1 on 2012-04-20
By Michael Chastain (mec.desktop@gmail.com)
Updated 2017-09-18

What’s a string_view, and Why Should You Care?

当我们创建一个函数并且这个函数有一个参数是用来接收常量字符串的,这时你有四个选择,其中有两个是你已经知道的,另外两个你或许还不知道:

void TakesCharStar(const char* s);             // C convention
void TakesString(const string& s);             // Old Standard C++ convention
void TakesStringView(absl::string_view s);     // Abseil C++ convention
void TakesStringView(std::string_view s);      // C++17 C++ convention

前两种方式最适合那种调用者提供参数和行参的类型是一致的,但是如果不一致是否需要进行转换(可能是const char*转换为string或者是sgtring转换为const char*)?

调用者需要将string转换为const char*是需要使用(高效但是不方便)c_str()函数:

void AlreadyHasString(const string& s) {
  TakesCharStar(s.c_str());               // explicit conversion
}

调用者需要将一个const char*转换为一个string的时候是不需要做任何额外事情的(这是一个好消息),但是这会导致编译器会隐式的创建一个临时的字符串(方便但是不高效),然后将const char*中的内容拷贝到这个string中(这是个不好的消息):

void AlreadyHasCharStar(const char* s) {
  TakesString(s); // compiler will make a copy
}

What to Do?

谷歌的首选是通过string_view的方式来接收字符串参数,在C++17中可以使用std::string_view来替代,在那些还没有使用C++17的代码中可以使用absl::string_view来替代。

一个string_view类的实例可以被认为是一个对现存的字符bufer的视图,具体来说string_view仅仅包含了一个指针和一个长度,仅用来标识一段字符数据并不拥有这段数据,不能通过这个视图来修改对应的数据。所以对一个string_view的拷贝是浅拷贝,是没有字符串数据的拷贝的。

string_view可以隐式的从一个const char*const string&构造出来,并且不会造成字符串数据的拷贝产生O(n)的复杂度,例如当传递一个const string&的时候,构造函数仅会产生O(1)的复杂度,当传递一个const char*的时候构造函数会自动的调用一个strlen函数(或者你可以传递两个参数给string_view)。

void AlreadyHasString(const string& s) {
  TakesStringView(s); // no explicit conversion; convenient!
}


void AlreadyHasCharStar(const char* s) {
  TakesStringView(s); // no copy; efficient!
}

因为string_view不拥有数据,所以被string_view所指向的字符串(类似于const char*)都必须有一个已知的生命周期,而且其生命周期要长于string_view对象自己。这意味着使用string_view来存储字符串通常是有问题的,你需要证明你引用的底层数据其生命周期要长于string_view对象自己的。

如果你的API仅仅是需要在一个单次调用中引用一个字符串数据,而且不会修改数据,那么接收一个string_view作为参数这是足够的。如果你还需要在调用后还引用这个数据,或者修复这个数据,那么你需要显示通过string(my_string_view)来将其转换string类型。

string_view添加到现存的代码中并不总是正确的,如果传递给这个函数的需要的就是一个string或者是一个const char*使用string_view并不会很高效。最佳的方案是从工具代码开始向上开始采用string_view来替换,或者是从一个新项目一开始就保持一致。

A Few Additional Notes

  • 和其他字符串类型不一样的点在于string_view传递的时候应该按照值拷贝的方式传递,就像传递intdouble类型一样,因为string_view就是一个小数值。
  • string_view不需要以NULL结尾,因此如果这样输出是不安全的:
printf("%s\n", sv.data()); // DONT DO THIS

然后,下面这样是可以的:
c++
printf("%.*s\n", static_cast<int>(sv.size()), sv.data());

  • 你应该像一个string或者const char*那样来输出string_view
std::cout << "Took '" << s << "'";
  • 在大多数情况下你将安全的将一个现存的接收const string&const char*参数的函数转换为string_view我们在执行此操作时遇到的唯一危险是,如果函数的地址已被占用,则会导致构建中断,因为所产生的函数指针类型将有所不同
  • 0
    点赞
  • 0
    评论
  • 1
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

相关推荐
<p style="color:#666666;"> <span style="font-size:14px;">本门课程重实战,将基础知识拆解到项目里,让你在项目情境里学知识。</span> </p> <p style="color:#666666;"> <span style="font-size:14px;">这样的学习方式能让你保持兴趣、充满动力,时刻知道学的东西能用在哪、能怎么用。</span> </p> <p style="color:#666666;"> <span style="font-size:14px;">平时不明白的知识点,放在项目里去理解就恍然大悟了。</span> </p> <p style="color:#666666;"> <span></span> </p> <p style="color:#666666;"> <span style="font-size:14px;"> </span> </p> <p style="color:#666666;"> <span style="color:#FF0000;font-size:14px;"><strong>一、融汇贯通</strong></span> </p> <p style="color:#666666;"> <span style="font-size:14px;">本视频采用了前后端分离的开发模式,前端使用Vue.js+Element UI实现了Web页面的呈现,后端使用Python 的Django框架实现了数据访问的接口,前端通过Axios访问后端接口获得数据。在学习完本章节后,真正理解前后端的各自承担的工作。</span> </p> <p style="color:#666666;"> <span style="font-size:14px;"> </span> </p> <p style="color:#666666;"> <span style="color:#FF0000;font-size:14px;"><strong>二、贴近实战</strong></span> </p> <p style="color:#666666;"> <span style="font-size:14px;">本系列课程为练手项目实战:学生管理系统v4.0的开发,项目包含了如下几个内容:项目的总体介绍、基本功能的演示、Vuejs的初始化、Element UI的使用、在Django中实现针对数据的增删改查的接口、在Vuejs中实现前端增删改查的调用、实现文件的上传、实现表格的分页、实现导出数据到Excel、实现通过Excel导入数据、实现针对表格的批量化操作等等,所有的功能都通过演示完成、贴近了实战</span> </p> <p style="color:#666666;"> <span style="font-size:14px;"> </span> </p> <p style="color:#666666;"> <span style="color:#FF0000;font-size:14px;"><strong>三、课程亮点</strong></span> </p> <p style="color:#666666;"> <span style="font-size:14px;">在本案例中,最大的亮点在于前后端做了分离,真正理解前后端的各自承担的工作。前端如何和后端交互</span> </p> <p style="color:#666666;"> <span style="font-size:14px;"> </span> </p> <p style="color:#666666;"> <span style="color:#FF0000;font-size:14px;"><strong>适合人群:</strong></span> </p> <p style="color:#666666;"> <span style="font-size:14px;">1、有Python语言基础、web前端基础,想要深入学习Python Web框架的朋友;</span> </p> <p style="color:#666666;"> <span style="font-size:14px;">2、有Django基础,但是想学习企业级项目实战的朋友;</span> </p> <p style="color:#666666;"> <span style="font-size:14px;">3、有MySQL数据库基础的朋友</span> </p> <p style="color:#666666;"> <span style="font-size:14px;"> </span> </p> <p style="color:#666666;"> <span style="font-size:14px;"><img alt="" src="https://img-bss.csdnimg.cn/202009070752197496.png" /><br /> </span> </p> <p style="color:#666666;"> <span style="font-size:14px;"><br /> </span> </p>
©️2020 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值