C++17 使用 std::string_view避免字符串拷贝优化程序性能

 更新时间:2020年10月24日 11:12:00   作者:半杯茶的小酒杯  
这篇文章主要介绍了C++17 使用 std::string_view避免字符串拷贝优化程序性能,帮助大家提高程序运行速度,感兴趣的朋友可以了解下

C++中std::string是日常Coding中经常使用的一个类,使用起来非常方便,但是也存在一些弊端。

如下代码,参数传递的过程发生了内存分配(Memory Allocation)和内存拷贝。

void fun(const std::string& s) {
  std::cout << s << std::endl;
}

const char* ch = "hello world";

// bad way, expensive if the string is long
fun(ch); 

再看下面的常用的字符串截取实现:

// very long string
std::string str = "lllloooonnnngggg sssstttrrriiinnnggg"; 

// bad way, expensive if the string is long
std::cout << str.substr(15, 10) << '\n';

为了进一步的压榨程序的性能,需要移除掉这些昂贵的字符串内存分配和拷贝操作。C++17中提供了std::string_view可以帮助我们实现这一功能,该类并不持有字符串的拷贝,而是与源字符串共享其内存空间。

string_view构造函数

constexpr basic_string_view() noexcept; (since C++17)
constexpr basic_string_view(const basic_string_view& other) noexcept = default; (since C++17)
constexpr basic_string_view(const CharT* s, size_type count);(since C++17)
constexpr basic_string_view(const CharT* s); (since C++17)
template<class It, class End>

虽然没有定义参数为std::string的std::string_view函数,下面的代码仍然可以通过编译。

std::string str("hello string view!");
std::string_view sview(str);

因为std::string类重载了std::string到std::string_view的转换操作符。

operator basic_string_view<charT, traits>() const noexcept;

std::string_view避免内存拷贝

有了string_view,我们就可以很好的解决文章开头提到的问题。

void fun(const std::string_view& s) {
  std::cout << s << std::endl;
}

const char* ch = "hello world, char";
fun(ch); 

const std::string str = "hello world, string";
fun(str);

fun({ch, 5});

有了std::string_view,函数参数不管是字符串数组指针,还是std::string,都不需要拷贝内存源字符串。

// very long string
std::string str = "lllloooonnnngggg sssstttrrriiinnnggg";

//Good way - No copies are created!
std::string_view view = str;

// string_view::substr returns a new string_view
std::cout << view.substr(15, 10) << '\n';

同理,字符串的substr()函数也不需要再进行拷贝了,这对于非常长的字符串,可以有效的提升程序的性能表现。

std::string_view注意事项

由于std::string_view并不持有字符串的内存,所以它的生命周期一定要比源字符串的生命周期长。一些典型的生命周期管理错误的例子:

std::string_view sv = std::string("hello world");

std::string_view fun() {
 std::string str("hello world");
 return std::string_view(str);
}

std::string_view的结尾并没有\0结束符,所以在输出std::string_view的时候要注意边界,如下代码:

#include <iostream>
#include <vector>
#include <string>
#include <string_view>

int main() {
  const char* ch = "hello world";
  
  std::string_view sv(ch, 2);
  
  std::cout << sv << std::endl;
  
  std::cout << sv.data() << std::endl;
  
  return 0;
}

程序输出:

he
hello world

std::cout << sv.data() << std::endl; 这行代码输出了hello world,这是因为sv仍然指向源字符串内存,调用sv.data()打印时,仍然沿用了C++对于字符串的约定,直到遇到结束符\0时,打印才结束,这时候就输出了完整的源字符串内容。当然这里明显是不符合预期的,尤其是std::string_view指向的字符串没有\0结束符的时候,程序很容易出现潜在的内存问题。所以此处一定要小心。

参考材料

https://riptutorial.com/cplusplus/example/6571/using-the-std–string-view-class

https://en.cppreference.com/w/cpp/string/basic_string_view

https://segmentfault.com/a/1190000018387368

以上就是C++17 使用 std::string_view避免字符串拷贝优化程序性能的详细内容,更多关于c++17 std::string_view的资料请关注脚本之家其它相关文章!

相关文章

  • C语言实现简单的三子棋游戏

    C语言实现简单的三子棋游戏

    这篇文章主要为大家详细介绍了C语言实现三子棋游戏,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-09-09
  • QT实现简单打地鼠游戏

    QT实现简单打地鼠游戏

    这篇文章主要为大家详细介绍了QT实现简单打地鼠游戏,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-12-12
  • C++小游戏BrickHit实例代码

    C++小游戏BrickHit实例代码

    本文通过实例代码给大家介绍了C++小游戏BrickHit的相关资料,需要的朋友可以参考下
    2018-02-02
  • C语言示例讲解do while循环语句的用法

    C语言示例讲解do while循环语句的用法

    在不少实际问题中有许多具有规律性的重复操作,因此在程序中就需要重复执行某些语句。一组被重复执行的语句称之为循环体,能否继续重复,决定循环的终止条件
    2022-06-06
  • C++继承的定义与注意事项

    C++继承的定义与注意事项

    这篇文章主要给大家介绍了关于C++继承的定义与注意事项的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-05-05
  • C语言实现文件读写操作

    C语言实现文件读写操作

    这篇文章主要为大家详细介绍了C语言实现文件读写操作,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-12-12
  • C++中关于Crt的内存泄漏检测的分析介绍

    C++中关于Crt的内存泄漏检测的分析介绍

    本篇文章介绍了,在C++中关于Crt的内存泄漏检测的分析说明。需要的朋友参考下
    2013-04-04
  • C语言实现天气信息管理系统

    C语言实现天气信息管理系统

    这篇文章主要介绍了C语言实现天气信息管理系统,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-06-06
  • 用c++实现x的y次幂的代码

    用c++实现x的y次幂的代码

    以下实例是对使用c++实现x的y次幂的解决方法进行了介绍。需要的朋友参考下
    2013-05-05
  • C++之CNoTrackObject类和new delete操作符的重载实例

    C++之CNoTrackObject类和new delete操作符的重载实例

    这篇文章主要介绍了C++之CNoTrackObject类和new delete操作符的重载实例,是C++程序设计中比较重要的概念,需要的朋友可以参考下
    2014-10-10

最新评论