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结束符的时候,程序很容易出现潜在的内存问题。所以此处⼀定要⼩⼼。
参考材料
以上就是C++17 使⽤ std::string_view避免字符串拷贝优化程序性能的详细内容,更多关于c++17 std::string_view的资料请关注其它相关⽂章!
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论