string_view
string_view是字符串的视图。C++提供的string效率是有点慢的,因为内存的开辟都在堆上。而C++17的string_view可以提高一些效率。所谓的SV(string_view)就是一个const字符串加上一个长度,你可以读取该字符串,但是你不能修改。
class string_view{
private:
const char* data_;
size_t size_;
};
这玩意也不是什么新东西了,C++17之前,就有人这样搞,因为SV对象只有一个指针和一个size_t的对象,所以拷贝和创建是非常轻量级的,传参可以直接by-value,使用起来体验非常好。 因为是string的视图,所以接口也都跟string很相似。
std::string str{"hello"};
const char* c_str = "hello";
char strings[]{"hello"};
std::string_view sv0;
std::string_view sv1{"hello"};
std::string_view sv2{str};
std::string_view sv3{c_str};
std::string_view sv4{strings};
std::string_view sv5{nullptr};
std::string_view{ std::begin(str), std::end(str) };
std::string_view sv5{sv1};
string_view的构造函数类似string,跟字符串有关的都可以使用,而且也支持iterator构造。string_view不要用nullptr来初始化。 string_view也支持拷贝构造,这样它们底层的指针都指向同一个字符串。
std::string str1{std::rbegin(str), std::rend(str)};
std::string_view sv6{std::rbegin(str), std::rend(str)};
用来举证底层是一个指针而已。不支持反向的"观察".
C++引入了std::literals::string_view_literals命名空间,重载了operator""sv操作符,
using namespace std::literals::string_view_literals;
void recv_string_view(std::string_view sv);
recv_string_view("hello"sv);
Visitor
SV也提供了operator[],
std::string_view sv{"hello"};
char first = sv[0];
sv[0] = 'a';
span
你想,string只不过是特殊的char数组罢了,string有了视图,那是不是所有的顺序表都可以有视图?没错,span就是这个东西。 我认为span与string_view最大的不同是,span支持修改。
template <class T>
class span{
private:
T* data_;
size_t size_;
};
我们可以通过span去管理内存连续的顺序表,比如普通的数组,std::vector,std::array等等。 在vector, array上,提供的自然是效率,因为span也是拷贝,构造简单的,代价很小。span在数组上也起了很大作用。在这方面,跟string_view一样。 而且,我们可以通过span管理数组,而非简简单单的“观察”。因为数组这个东西吧,不太面向对象。我们无法通过一个数组的对象得到数组的一系列特性。
int array[]{1, 2, 3};
array.size();
这里,我们无法仅仅通过array这个对象得到它的长度。而且array传参还会退化。有了span,我们可以实现。
int array[]{1, 2, 3};
std::span sp{array};
sp.size();
sp[0] = 3;
span可以理解为一个面向对象版本的数组。而且当span发生错误时,我们会给出明确的断言,out of span range,使用起来也很方便,且不用担心效率。 span的接口也非常简单,不再赘述。
|