C++ string_view


std::string_view 是C++17引入的一个轻量级、非拥有的字符串视图类,定义于 <string_view> 头文件中。它提供了一种高效且安全的方式来处理字符串数据,而无需复制字符串内容

1、 基本概念

std::string_view 本质上是对一个字符串序列的引用,它并不拥有字符串数据,只是持有指向字符串数据的指针和长度信息。这使得它在处理字符串时避免了不必要的内存分配和复制操作,提高了程序的性能。

主要用途

  • 函数参数传递:当函数需要处理字符串但不需要拥有字符串所有权时,可以使用 std::string_view 作为参数,这样可以避免不必要的字符串复制。
  • 临时字符串处理:在处理临时字符串或者子字符串时,使用 std::string_view 可以避免创建新的 std::string 对象,从而提高效率。

示例代码

以下是一个简单的示例,展示了 std::string_view 的基本用法:

#include <iostream>
#include <string_view>

// 接受 std::string_view 作为参数的函数
void printStringView(std::string_view sv) {
    std::cout << "String view content: " << sv << std::endl;
}

int main() {
    // 从 C 风格字符串创建 std::string_view
    const char* cstr = "Hello, World!";
    std::string_view sv1(cstr);

    // 从 std::string 创建 std::string_view
    std::string str = "Hello, C++!";
    std::string_view sv2(str);

    // 调用函数打印 std::string_view 内容
    printStringView(sv1);
    printStringView(sv2);

    return 0;
}

代码解释

  1. 包含头文件:包含 <iostream> 用于输入输出,<string_view> 用于使用 std::string_view
  2. 定义函数:定义了一个接受 std::string_view 作为参数的函数 printStringView,用于打印字符串视图的内容。
  3. 创建 std::string_view
    • 从 C 风格字符串创建 std::string_viewstd::string_view sv1(cstr);
    • std::string 创建 std::string_viewstd::string_view sv2(str);
  4. 调用函数:调用 printStringView 函数打印字符串视图的内容。

注意事项

  • 生命周期管理:由于 std::string_view 不拥有字符串数据,它所引用的字符串数据必须在 std::string_view 的生命周期内保持有效。否则,访问 std::string_view 可能会导致未定义行为。
  • 不可修改性std::string_view 是只读的,不能直接修改其内容。如果需要修改字符串,应该使用 std::string

常用成员函数

  • length()size():返回字符串视图的长度。
  • data():返回指向字符串数据的指针。
  • substr():返回一个新的 std::string_view,表示原字符串视图的子字符串。
  • starts_with()ends_with():检查字符串视图是否以指定的前缀或后缀开头或结尾。
  • find():查找指定子字符串或字符的第一次出现位置。

以下是一个使用这些成员函数的示例:

#include <iostream>
#include <string_view>

int main() {
    std::string_view sv = "Hello, World!";

    // 获取字符串视图的长度
    std::cout << "Length: " << sv.length() << std::endl;

    // 获取子字符串
    std::string_view sub = sv.substr(0, 5);
    std::cout << "Substring: " << sub << std::endl;

    // 检查前缀
    if (sv.starts_with("Hello")) {
        std::cout << "Starts with 'Hello'" << std::endl;
    }

    // 查找字符
    size_t pos = sv.find(',');
    if (pos != std::string_view::npos) {
        std::cout << "Comma found at position: " << pos << std::endl;
    }

    return 0;
}

通过使用 std::string_view,可以在不复制字符串数据的情况下高效地处理字符串,从而提高程序的性能和效率。

2、对比string

在实际应用里,std::string_view 相较于 std::string 存在不少优势,下面从性能、灵活性和安全性等方面展开详细介绍。

性能优势

避免内存分配与复制

std::string 会拥有字符串数据,在创建、赋值或者传递时,通常需要进行内存分配与数据复制操作。而 std::string_view 只是对已有字符串数据的引用,不拥有数据,所以不会产生额外的内存分配和复制开销。

下面是一个简单示例,能体现出两者在性能上的差异:

#include <iostream>
#include <string>
#include <string_view>
#include <chrono>

// 使用 std::string 作为参数的函数
void processString(const std::string& str) {
    // 模拟处理操作
    std::cout << str.length() << std::endl;
}

// 使用 std::string_view 作为参数的函数
void processStringView(std::string_view sv) {
    // 模拟处理操作
    std::cout << sv.length() << std::endl;
}

int main() {
    const char* cstr = "This is a long string for testing performance.";

    // 测试 std::string 的性能
    auto start1 = std::chrono::high_resolution_clock::now();
    for (int i = 0; i < 1000000; ++i) {
        processString(cstr);
    }
    auto end1 = std::chrono::high_resolution_clock::now();
    auto duration1 = std::chrono::duration_cast<std::chrono::milliseconds>(end1 - start1).count();

    // 测试 std::string_view 的性能
    auto start2 = std::chrono::high_resolution_clock::now();
    for (int i = 0; i < 1000000; ++i) {
        processStringView(cstr);
    }
    auto end2 = std::chrono::high_resolution_clock::now();
    auto duration2 = std::chrono::duration_cast<std::chrono::milliseconds>(end2 - start2).count();

    std::cout << "Time taken by std::string: " << duration1 << " ms" << std::endl;
    std::cout << "Time taken by std::string_view: " << duration2 << " ms" << std::endl;

    return 0;
}

在这个示例中,processString 函数接收 std::string 类型的参数,每次调用时都会进行字符串复制;而 processStringView 函数接收 std::string_view 类型的参数,不会进行复制操作。通过计时可以发现,使用 std::string_view 能显著提升性能。

轻量级数据结构

std::string_view 一般只包含一个指向字符串数据的指针和一个长度信息,其内存开销较小。相比之下,std::string 除了存储字符串数据外,还需要额外的空间来管理内存,如存储容量信息、分配器等。

灵活性优势

支持多种字符串源

std::string_view 可以从多种类型的字符串源创建,包括 std::string、C 风格字符串(const char*)以及字符数组等。这使得它在处理不同类型的字符串时更加灵活。

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

void printStringView(std::string_view sv) {
    std::cout << sv << std::endl;
}

int main() {
    std::string str = "Hello, std::string!";
    const char* cstr = "Hello, C-style string!";
    char arr[] = {'H', 'e', 'l', 'l', 'o', '\0'};

    printStringView(str);
    printStringView(cstr);
    printStringView(arr);

    return 0;
}
方便进行子字符串操作

std::string_view 提供了 substr 等成员函数,能够方便地获取原字符串的子字符串,而且不会复制子字符串的数据,效率较高。

#include <iostream>
#include <string_view>

int main() {
    std::string_view sv = "Hello, World!";
    std::string_view sub = sv.substr(0, 5);
    std::cout << sub << std::endl;
    return 0;
}

安全性优势

只读特性

std::string_view 是只读的,不能直接修改其内容。这有助于避免意外修改字符串数据,提高程序的安全性。如果需要修改字符串,应该使用 std::string

#include <iostream>
#include <string_view>

int main() {
    std::string_view sv = "Read-only string";
    // 以下代码会导致编译错误,因为 std::string_view 是只读的
    // sv[0] = 'W'; 
    return 0;
}

综上所述,在只需要对字符串进行读取操作、不需要拥有字符串所有权的场景中,使用 std::string_view 可以提高程序的性能和灵活性,同时增强代码的安全性。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值