C17 string_view引入

String_view简介

String_view是C++17引入的一个新特性,它主要解决了以下问题:

1. 减少内存分配和拷贝操作:
   - 传统的std::string对象需要动态分配内存并拷贝字符串数据,这会带来性能损耗。
   - string_view则仅仅持有一个指向字符串数据的指针,不需要额外的内存分配和拷贝,提高了性能。

2. 避免字符串所有权问题:
   - std::string对象需要管理字符串数据的生命周期,容易出现悬垂指针问题
   - string_view不拥有字符串数据,不需要管理其生命周期,避免了所有权问题。

3. 支持各种字符串类型:
   - string_view可以适用于std::string、C风格字符串数组,以及其他类型的字符串数据。
   - 这使得代码可以更加通用和灵活。

总之,string_view的引入大大提高了C++处理字符串的性能和灵活性,是C++17中一个非常实用的新特性。

以减少内存分配和拷贝操作 进行探讨

举例

高明的开发者或许一眼就能看出问题,在此期间有一次不必要的copy 这大大的浪费了程序的性能消耗,问题就在于 myString 实参传递和形参使用string 并不是引用。
void processString(std::string str) {
    // 对字符串str进行一些操作
    std::cout << "Processing string: " << str << std::endl;
}

std::string myString = "Hello, world!";
processString(myString); // 需要拷贝myString

在这种情况下,当我们调用processString(myString)时,需要进行以下操作:
创建一个临时的std::string对象,并将myString拷贝到该对象中。
将这个临时对象作为参数传递给processString函数。
在函数内部,还需要再次拷贝这个临时对象。



引入stringview后,代码可读性更强,不需要理会我到底加没加引用。

void processStringView(std::string_view str) {
    // 对字符串str进行一些操作
    std::cout << "Processing string view: " << str << std::endl;
}

std::string myString = "Hello, world!";
processStringView(myString); 

在这种情况下,当我们调用processStringView(myString)时,只需要进行以下操作:
将myString隐式转换为std::string_view类型,这只需要传递一个指针,不需要进行任何拷贝操作。
将这个std::string_view对象传递给processStringView函数。

以避免字符串所有权问题 进行探讨

悬垂引用

举一个简单的例子来解释悬垂引用:

int* getPtr() {
    int x = 42;
    return &x;
}

int* p = getPtr();
std::cout << *p << std::endl; // 悬垂引用,x已经被销毁

回到string

//先看传统const string &引发的问题 悬垂引用
const std::string & fun(const std::string &str){
    cout<<str<<endl; //引用右值 输出 此时生命周期还是存在的
    return str; //返回回去
}   

auto str = fun("hello word");  //首先这里传递右值 ,接住当前的右值
cout<<str<<endl;          //此时该右值已经不存在了,为什么能运行?这是因为C++编译器在某些情况下可以进行特殊的优化,避免了悬垂引用的问题。
 
哪些优化?
编译器可以执行以下优化:
字符串字面量"hello word"是存储在只读内存区域的,它的生命周期贯穿整个程序的执行。
当我们调用fun("hello word")时,编译器可以将字符串字面量直接传递给fun函数,而不需要创建临时的std::string对象。
因此,当我们在fun函数中返回str时,实际上返回的是对字符串字面量的引用,而不是一个悬垂引用。
在main函数中,auto str = fun("hello word");这行代码,编译器可以将返回的引用直接绑定到str变量上,不需要额外的拷贝操作。
//下列例子 包是悬垂引用,虽然不会立即造成程序问题,为程序稳定埋下伏笔。
auto str = fun(string("hello word")); 

那我们新版本stringview的写法呢?

std::string_view fun(std::string_view str) {
    cout << str << endl; // 可以正常输出
    return str; // 返回string_view,不会引发悬垂引用问题
}

auto str = fun("hello word");
cout << str << endl;

在这种情况下,确实没有产生任何拷贝操作。让我们仔细分析一下:
在fun函数中,我们接受一个std::string_view类型的参数str。
当我们在main函数中调用fun("hello word")时,编译器会自动将字符串字面量"hello word"转换为std::string_view类型,并传递给fun函数。
在fun函数内部,我们直接使用并返回了str参数,也就是对字符串字面量的引用。
在main函数中,我们将fun函数的返回值赋给了auto str。这里,str变量也是对字符串字面量的引用,没有发生任何拷贝操作。

总结:使用string_view会直接对字面量"hello word"进行引用,也就是说不会产生任何的copy.

支持各种字符串类型

第三点就不探讨了,因为在使用string时,也会兼容char,编译器会帮我们做隐式类型转换。

看点示例吧

void printLength(std::string_view str) {
    std::cout << "Length: " << str.length() << std::endl;
}

std::string myString = "Hello, world!";
printLength(myString);  // 输出: Length: 13


c风格
const char* cstr = "C-style string";
printLength(cstr);      // 输出: Length: 14


自定义
class MyString {
public:
    const char* data() const { return m_data; }
    size_t size() const { return strlen(m_data); }

private:
    char m_data[20] = "Custom string";
};

MyString customString;
printLength(customString); // 输出: Length: 13

 总结

stringview 好处:可读性更强了,开发者不必理会字符串传递规则,直接使用就能写出高性能的代码,把工作重点放在业务上。

`std::string_view`虽然有很多优点,但也存在一些潜在的缺点,需要开发者注意:

1. 所有权问题:
   - `std::string_view`不拥有它所引用的字符串数据,因此如果原始字符串数据在`std::string_view`对象的生命周期结束前被销毁,就会出现悬垂引用的问题。开发者需要谨慎管理字符串数据的生命周期。

2. 线程安全问题:
   - 因为`std::string_view`只是持有一个指向字符串数据的指针,如果该字符串数据被并发修改,则`std::string_view`的行为是未定义的。开发者需要确保字符串数据在`std::string_view`的生命周期内保持不变。

3. 缺乏部分功能:
   - `std::string_view`缺乏一些`std::string`常见的功能,如字符串修改、格式化等。如果需要这些功能,仍然需要使用`std::string`。

4. 潜在的性能问题:
   - 虽然`std::string_view`可以减少内存分配和拷贝操作,但在某些情况下,频繁创建和销毁`std::string_view`对象也可能会影响性能。开发者需要权衡使用`std::string_view`的利弊。

5. 兼容性问题:项目用的c11,则无法使用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值