【库函数】在什么时候使用 string_view 代替 string

前言

C++17增加了std::string_view它在很多情况会优于使用std::string

尤其是用做函数形参的时候,使用std::string_view基本一定优于老式的const std::string&这种写法。

了解std::string_view

在讲述它的优越性之前,我们应该先介绍一下它。

首先,它顾名思义,就是一个字符串视图,它和std::string不一样,不是一个可变的字符串类型。

它只是用来指代“字符串”(这个字符串可以指代的东西很多)的,并不拥有所有权,自然也不可变

通常实现只保有两个数据成员:一个指向字符串的指针,一个表示字符串的的size(通常是size_t类型)。

通常64位系统下大小为16个字节。

了解std::string

class string {//简单示例,实际不可能如此
public:
    // all 83 member functions
private:
    char* m_data;
    size_type m_size;
    size_type m_capacity;
    std::array<char, 16> m_sso;
};

对于 64 位系统,每个字符串std::string有 24 个字节的“开销”(sizecapacitydata),另外还有 16 个字节用于 SSO 缓冲区。

加起来也就是40。

实际使用

老式写法

void func(const std::string&s){
    std::cout << s << '\n';
}

看起来没有任何问题,但其实在很多传参调用的情况下,开销是很大的。

std::string s{"乐呵"};
func("乐呵");
func(s);

你觉得上面哪个调用,谁的开销更大

func("乐呵");,这里我们传入的是字符串字面量,它和std::string不是一个类型,这里实际上需要调用std::string的转换构造函数,在当前构造出一个临时的std::string对象,也就是一个纯右值表达式。

const std::string&可以接纯右值表达式,没问题,并且延长临时对象的生存期,可以在函数局部使用。

const char* p = "乐呵";
func(p);//传指针也和上面说的差不多。

另外,使用const std::string&还更容易造成一些bug,比如:

 const std::string& f(const std::string& str) {
    return str;
}
int main() {
    auto& ret = f("哈哈");
    std::cout << ret << '\n';
}

const std::string& str接纯右值表达式是没问题。但是它最后还想返回这个对象的引用,就不对了。

在函数调用中绑定到函数形参的临时量,存在到含这次函数调用的全表达式结尾为止:如果函数返回一个生命长于全表达式的引用,那么它会成为悬垂引用。

使用std::string_view

void func(std::string_view s){
    std::cout << s << '\n';
}

int main(){
    std::string s{"乐呵"};
    const char* p = "乐呵";
    func("乐呵");
    func(s);
    func(p);
}

std::string有一个到std::string_view转换函数,其他的都是正常走std::string_view的构造函数

std::string_view 只是一个视图,用来指代原字符串的,保有一个size和一个指针即可。

新增加的库基本上不会再以const std::string&这种作为形参,比如std::formatstd::vformat

总结

如果你能用std::string_view,那么请使用。至少在用作接口的时候,一定是。

posted @ 2023-09-12 08:30  RioTian  阅读(99)  评论(0编辑  收藏  举报