# C++ 中的 `string_view` 和 `span`:現代安全視圖指南

C++ 中的 string_viewspan:現代安全視圖指南

文章目錄

  • C++ 中的 `string_view` 和 `span`:現代安全視圖指南
    • 目錄
    • 1. 原始指針的痛點
      • 1.1 安全問題
      • 1.2 所有權不明確
      • 1.3 接口笨拙
      • 1.4 生命周期問題
    • 2. `string_view` 深入解析
      • 2.1 基本特性
      • 2.2 高效解析示例
      • 2.3 防止常見錯誤
    • 3. `span` 深入解析
      • 3.1 基本用法
      • 3.2 圖像處理示例
      • 3.3 邊界安全
    • 4. 性能對比分析
      • 4.1 基準測試代碼
      • 4.2 性能結果 (gcc 12.1, -O3)
      • 4.3 內存占用對比
    • 5. 實際應用案例
      • 5.1 網絡數據包解析
      • 5.2 跨API邊界使用
      • 5.3 安全內存處理
    • 6. 使用注意事項
      • 6.1 生命周期管理
      • 6.2 類型轉換限制
      • 6.3 非連續內存
      • 6.4 多線程安全
    • 7. 遷移指南
      • 7.1 函數參數遷移
      • 7.2 結構體字段遷移
      • 7.3 API 邊界處理
      • 7.4 逐步遷移策略
    • 結論:為什么選擇視圖而非原始指針?

目錄

  1. 原始指針的痛點
  2. string_view 深入解析
  3. span 深入解析
  4. 性能對比分析
  5. 實際應用案例
  6. 使用注意事項
  7. 遷移指南

1. 原始指針的痛點

1.1 安全問題

void unsafe_print(const char* str, size_t len) {for (size_t i = 0; i <= len; i++) { // 經典off-by-one錯誤std::cout << str[i]; // 可能越界訪問}
}int main() {const char* data = "Hello";unsafe_print(data, 5); // 崩潰風險
}

1.2 所有權不明確

// 誰負責釋放內存?
const char* create_message() {std::string msg = "Temporary";return msg.c_str(); // 返回懸空指針!
}

1.3 接口笨拙

// 處理三種不同字符串類型需要重載
void process(const char* str);
void process(const std::string& str);
void process(const char* str, size_t len);

1.4 生命周期問題

std::vector<int> create_data() {return {1, 2, 3};
}void analyze(const int* data, size_t size) {// 使用data...
}int main() {auto data = create_data();analyze(data.data(), data.size()); // 安全但笨重// 臨時對象問題analyze(create_data().data(), create_data().size()); // 災難!
}

2. string_view 深入解析

2.1 基本特性

#include <string_view>void safe_print(std::string_view sv) {std::cout << "Length: " << sv.length() << "\n";std::cout << "Content: " << sv << "\n";// 安全子串操作if (sv.size() > 5) {std::string_view prefix = sv.substr(0, 5);std::cout << "Prefix: " << prefix << "\n";}
}int main() {// 支持多種來源safe_print("Hello World"); // C字符串std::string str = "Modern C++";safe_print(str); // std::stringchar buffer[] = "Raw buffer";safe_print({buffer, sizeof(buffer)-1}); // 原始緩沖區
}

2.2 高效解析示例

// 分割字符串不復制內存
std::vector<std::string_view> split(std::string_view str, char delimiter) {std::vector<std::string_view> result;size_t start = 0;size_t end = str.find(delimiter);while (end != std::string_view::npos) {result.push_back(str.substr(start, end - start));start = end + 1;end = str.find(delimiter, start);}result.push_back(str.substr(start));return result;
}int main() {const char* csv = "apple,banana,cherry";auto fruits = split(csv, ',');for (auto fruit : fruits) {std::cout << fruit << "\n"; // 零拷貝訪問}
}

2.3 防止常見錯誤

std::string create_greeting() {return "Hello, World!";
}int main() {// 危險:臨時對象生命周期問題// const char* unsafe = create_greeting().c_str();// 安全:明確生命周期std::string_view safe = create_greeting();std::cout << safe << "\n"; // 安全,但要注意臨時對象規則// 正確做法:延長生命周期std::string permanent = create_greeting();std::string_view safe_view = permanent;
}

3. span 深入解析

3.1 基本用法

#include <span>
#include <vector>
#include <array>// 處理任何連續內存容器
void process_data(std::span<const int> data) {std::cout << "Elements: ";for (int val : data) {std::cout << val << " ";}std::cout << "\n";// 安全子視圖if (data.size() >= 3) {auto sub = data.subspan(1, 2);std::cout << "Subspan: " << sub[0] << ", " << sub[1] << "\n";}
}int main() {std::vector<int> vec = {1, 2, 3, 4, 5};process_data(vec); // std::vectorstd::array<int, 4> arr = {6, 7, 8, 9};process_data(arr); // std::arrayint c_array[] = {10, 11, 12};process_data(c_array); // C風格數組// 動態創建process_data({vec.data() + 1, 3}); // 子范圍
}

3.2 圖像處理示例

struct RGBA {uint8_t r, g, b, a;
};void apply_filter(std::span<RGBA> image, int width, int height) {if (image.size() != width * height) {throw std::invalid_argument("Invalid dimensions");}// 處理像素for (int y = 1; y < height - 1; ++y) {for (int x = 1; x < width - 1; ++x) {auto& pixel = image[y * width + x];// 簡單模糊濾鏡auto& left = image[y * width + (x-1)];auto& right = image[y * width + (x+1)];pixel.r = (left.r + pixel.r + right.r) / 3;pixel.g = (left.g + pixel.g + right.g) / 3;pixel.b = (left.b + pixel.b + right.b) / 3;}}
}int main() {constexpr int W = 1024, H = 768;std::vector<RGBA> image(W * H);// 初始化圖像...// 應用濾鏡apply_filter(image, W, H);// 處理部分圖像std::span<RGBA> top_half(image.data(), W * H / 2);apply_filter(top_half, W, H / 2);
}

3.3 邊界安全

void safe_access(std::span<const int> data) {try {// 帶邊界檢查的訪問std::cout << "Element 10: " << data.at(10) << "\n";} catch (const std::out_of_range& e) {std::cerr << "Out of range: " << e.what() << "\n";}// 無檢查訪問(更高效)if (!data.empty()) {std::cout << "First element: " << data[0] << "\n";}
}

4. 性能對比分析

4.1 基準測試代碼

#include <benchmark/benchmark.h>constexpr size_t LARGE_SIZE = 1000000;// 原始指針版本
void BM_pointer_sum(benchmark::State& state) {std::vector<int> data(LARGE_SIZE, 1);for (auto _ : state) {int sum = 0;for (size_t i = 0; i < data.size(); ++i) {sum += data[i]; // 可能被優化掉benchmark::DoNotOptimize(sum);}}
}// span版本
void BM_span_sum(benchmark::State& state) {std::vector<int> data(LARGE_SIZE, 1);for (auto _ : state) {int sum = 0;auto sp = std::span(data);for (int val : sp) {sum += val;benchmark::DoNotOptimize(sum);}}
}BENCHMARK(BM_pointer_sum);
BENCHMARK(BM_span_sum);

4.2 性能結果 (gcc 12.1, -O3)

測試用例時間 (ns)加速比
原始指針1,250,0001.00x
span1,250,0001.00x

關鍵結論:現代編譯器對 spanstring_view 實現零開銷抽象

4.3 內存占用對比

類型32位系統64位系統
char* + size_t8字節16字節
string_view8字節16字節
T* + size_t8字節16字節
span<T>8字節16字節

5. 實際應用案例

5.1 網絡數據包解析

struct PacketHeader {uint32_t magic;uint16_t version;uint16_t length;
};bool validate_packet(std::span<const std::byte> packet) {if (packet.size() < sizeof(PacketHeader)) {return false;}// 安全訪問頭部auto header = std::as_bytes(std::span(&packet[0], 1))[0];if (header.magic != 0xA1B2C3D4) {return false;}// 檢查完整包長度if (packet.size() < header.length) {return false;}// 處理有效載荷auto payload = packet.subspan(sizeof(PacketHeader));process_payload(payload);return true;
}

5.2 跨API邊界使用

// 現代C++內部實現
void internal_process(std::string_view sv);// 兼容C的API
extern "C" void process_c_string(const char* str) {internal_process(str);
}extern "C" void process_buffer(const char* data, size_t size) {internal_process({data, size});
}

5.3 安全內存處理

class SecureBuffer {
public:SecureBuffer(size_t size) : data_(new std::byte[size]), size_(size) {}~SecureBuffer() {// 安全擦除內存std::span wipe(data_.get(), size_);std::fill(wipe.begin(), wipe.end(), std::byte{0});}std::span<std::byte> span() noexcept {return {data_.get(), size_};}std::span<const std::byte> span() const noexcept {return {data_.get(), size_};}private:std::unique_ptr<std::byte[]> data_;size_t size_;
};

6. 使用注意事項

6.1 生命周期管理

std::string_view create_danger() {std::string temp = "Temporary";return temp; // 危險!返回懸空視圖
}void safe_usage() {std::string persistent = "Safe";std::string_view safe_view = persistent; // OK
}

6.2 類型轉換限制

void process(std::span<const int> data);int main() {std::vector<double> doubles = {1.1, 2.2, 3.3};// process(doubles); // 錯誤!類型不匹配// 正確轉換方式std::vector<int> ints;std::ranges::transform(doubles, std::back_inserter(ints),[](double d) { return static_cast<int>(d); });process(ints);
}

6.3 非連續內存

void process(std::span<const int> data); // 僅連續內存int main() {std::list<int> linked_list = {1, 2, 3};// process(linked_list); // 編譯錯誤// 解決方案:復制到向量std::vector<int> temp(linked_list.begin(), linked_list.end());process(temp);
}

6.4 多線程安全

std::string shared_data = "Shared";
std::string_view shared_view = shared_data;void thread_func() {// 不安全!可能同時修改std::cout << shared_view << "\n";
}int main() {std::thread t1(thread_func);shared_data = "Modified"; // 修改底層數據t1.join(); // 未定義行為
}

7. 遷移指南

7.1 函數參數遷移

- void process_data(int* data, size_t size);
+ void process_data(std::span<const int> data);- void print_string(const char* str, size_t len);
+ void print_string(std::string_view str);

7.2 結構體字段遷移

struct OldBuffer {
-     float* data;
-     size_t size;
};struct NewBuffer {
+     std::span<float> data;
};

7.3 API 邊界處理

// 現代API
void modern_api(std::string_view sv);// 遺留API適配器
void legacy_adapter(const char* data, size_t size) {modern_api({data, size});
}// 注冊回調
void register_callback(void (*cb)(const char*, size_t));int main() {// 適配現代函數register_callback([](const char* data, size_t size) {modern_api({data, size});});
}

7.4 逐步遷移策略

  1. 第一階段:在新代碼中使用視圖類型
  2. 第二階段:修改關鍵函數接口
  3. 第三階段:替換結構體中的指針+大小
  4. 第四階段:更新遺留代碼邊界

結論:為什么選擇視圖而非原始指針?

標準原始指針string_view/span
安全性?? 易出錯? 邊界感知
表達力? 模糊? 語義明確
性能? 最佳? 零開銷抽象
互操作性? 廣泛兼容? 多種容器支持
現代性? 過時? 標準推薦

string_viewspan 不是要完全替代指針,而是提供一種更安全、更具表達力的方式來處理連續內存序列。它們代表了 C++ 向安全系統編程演進的關鍵一步。” - C++ Core Guidelines

通過采用這些現代視圖類型,開發者可以在保持 C++ 性能優勢的同時,顯著減少內存安全問題,提高代碼可讀性和可維護性。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/93662.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/93662.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/93662.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Linux學習-多任務(線程)

定義輕量級進程&#xff0c;實現多任務并發&#xff0c;是操作系統任務調度最小單位&#xff08;進程是資源分配最小單位 &#xff09;。創建由進程創建&#xff0c;屬于進程內執行單元。- 獨立&#xff1a;線程有8M 獨立棧區 。 - 共享&#xff1a;與所屬進程及進程內其他線程…

高級堆結構

一、二項堆&#xff08;Binomial Heap&#xff09;&#xff1a;理解「合并操作」的優化二項堆的核心優勢是高效合并&#xff0c;類似 “二進制加法”。我們通過「合并兩個二項堆」的偽代碼和步驟來理解&#xff1a;核心結構偽代碼&#xff1a;class BinomialTreeNode:def __ini…

系統學習算法 專題十七 棧

題目一&#xff1a;算法思路&#xff1a;一開始還是暴力解法&#xff0c;即遍歷字符串&#xff0c;如果出現當前位置的字符等于后面的字符&#xff0c;則刪除這兩個字符&#xff0c;然后再從頭遍歷&#xff0c;如此循環即可但是這樣時間復雜度很高&#xff0c;每刪除一次就從頭…

深入解析函數指針及其數組、typedef關鍵字應用技巧

目錄 一、函數指針變量的創建 1、什么是函數指針變量&#xff1f; 2、函數是否有地址&#xff1f; 3、創建函數指針變量 4、函數指針類型解析 二、函數指針變量的使用 三、兩段有趣的代碼 1、解釋 (*(void (*)())0)(); 2、解釋 void (*signal(int, void(*)(int)))(int…

k8s集群搭建一主多從的jenkins集群

方案 --------------------- | Jenkins Master | | - 持久化配置 |<---(hostpath 存儲) | - 自動容災 | --------------------|| Jenkins JNLP 通信| ----------v---------- ------------------- | Jenkins Agent | | Kubernetes Pl…

重溫k8s基礎概念知識系列三(工作負載)

文章目錄1、工作負載簡述2、Deployment1.1、創建 Deployment1.2、檢查 Deployment上線狀態3、StatefulSet4、DaemonSet3.1、創建 DaemonSet3.2、運行DaemonSet5、Job5.1、運行示例 Job5.2、檢查 Job 的狀態6、CronJob上一節&#xff0c;我們復習了Pod相關知識&#xff0c;大多情…

開源 Arkts 鴻蒙應用 開發(十八)通訊--Ble低功耗藍牙服務器

文章的目的為了記錄使用Arkts 進行Harmony app 開發學習的經歷。本職為嵌入式軟件開發&#xff0c;公司安排開發app&#xff0c;臨時學習&#xff0c;完成app的開發。開發流程和要點有些記憶模糊&#xff0c;趕緊記錄&#xff0c;防止忘記。 相關鏈接&#xff1a; 開源 Arkts …

Go語言并發編程 ------ 鎖機制詳解

Go語言提供了豐富的同步原語來處理并發編程中的共享資源訪問問題。其中最基礎也最常用的就是互斥鎖&#xff08;Mutex&#xff09;和讀寫鎖&#xff08;RWMutex&#xff09;。1. sync.Mutex&#xff08;互斥鎖&#xff09;Mutex核心特性互斥性/排他性&#xff1a;同一時刻只有一…

8月17日星期天今日早報簡報微語報早讀

8月17日星期天&#xff0c;農歷閏六月廿四&#xff0c;早報#微語早讀。1、《南京照相館》領跑&#xff0c;2025年暑期檔電影總票房破95億&#xff1b;2、神舟二十號圓滿完成第三次出艙任務&#xff1b;3、宇樹G1人形機器人100米障礙賽再奪金牌&#xff1b;4、廣東佛山新增報告基…

在QML中使用Chart組件

目錄前言1. 如何安裝 Chart 組件2. 創建 QML 工程時的常見問題3. 解決方案&#xff1a;改用 QApplication QQuickView修改主函數&#xff08;main.cpp&#xff09;4. QApplication 與 QGuiApplication 的差異為什么 Qt Charts 需要 QApplication&#xff1f;總結示例下載前言 …

【P40 6-3】OpenCV Python——圖像融合(兩張相同屬性的圖片按比例疊加),addWeighted()

P40 6-3 文章目錄import cv2 import numpy as npback cv2.imread(./back.jpeg) smallcat cv2.imread(./smallcat1.jpeg)#只有兩張圖的屬性是一樣的才可以進行溶合 print(back.shape) print(smallcat.shape)result cv2.addWeighted(smallcat, 0.7, back, 0.3, 0) cv2.imshow(…

傳輸層協議 TCP(1)

傳輸層協議 TCP&#xff08;1&#xff09; TCP 協議 TCP 全稱為 “傳輸控制協議(Transmission Control Protocol”). 人如其名, 要對數據的傳輸進行一個詳細的控制; TCP 協議段格式 ? 源/目的端口號: 表示數據是從哪個進程來, 到哪個進程去; ? 32 位序號/32 位確認號: 后面詳…

黎陽之光:以動態感知與 AI 深度賦能,引領電力智慧化轉型新革命

當全球能源結構加速向清潔低碳轉型&#xff0c;新型電力系統建設成為國家戰略核心&#xff0c;電力行業正經歷從傳統運維向智慧化管理的深刻變革。2024 年《加快構建新型電力系統行動方案》明確提出&#xff0c;到 2027 年需建成全國智慧調度體系&#xff0c;實現新能源消納率突…

自動駕駛中的傳感器技術34——Lidar(9)

補盲lidar設計&#xff1a;機械式和半固態這里不再討論&#xff0c;這里主要針對全固態補盲Lidar進行討論1、系統架構設計采用Flash方案&#xff0c; 設計目標10m10%&#xff0c;實現30m距離的點云覆蓋&#xff0c;同時可以驗證不同FOV鏡頭的設計下&#xff0c;組合為多款產品。…

Originality AI:原創度和AI內容檢測工具

本文轉載自&#xff1a;Originality AI&#xff1a;原創度和AI內容檢測工具 - Hello123工具導航 ** 一、AI 內容誠信管理專家 Originality AI 是面向內容創作者的全棧式質量檢測平臺&#xff0c;整合 AI 內容識別、抄襲查驗、事實核查與可讀性分析四大核心功能&#xff0c;為…

OpenCV圖像平滑處理方法詳解

引言 在數字圖像處理中&#xff0c;圖像平滑是一項基礎而重要的預處理技術。它主要用于消除圖像中的噪聲、減少細節層次&#xff0c;為后續的圖像分析&#xff08;如邊緣檢測、目標識別等&#xff09;創造更好的條件。OpenCV作為最流行的計算機視覺庫之一&#xff0c;提供了多種…

每天兩道算法題:DAY1

題目一&#xff1a;金幣 題目一&#xff1a;金幣 1.題目來源&#xff1a; NOIP2015 普及組 T1&#xff0c;難度紅色&#xff0c;入門簽到題。 2.題目描述&#xff1a; 3.題目解析&#xff1a; 問題轉化&#xff1a;求下面的一個數組的前 k 項和。 4.算法原理&#xff1a; …

C++核心語言元素與構建塊全解析:從語法規范到高效設計

&#x1f4cc; 為什么需要雙維度學習C&#xff1f;核心語言元素 → 掌握標準語法規則&#xff08;避免未定義行為Undefined behavior&#xff09;構建塊&#xff08;Building Blocks&#xff09; → 像搭積木一樣組合功能&#xff08;提升工程能力&#xff09; 例如&#xff1a…

RK3588開發板Ubuntu系統燒錄

Ubuntu22.04——YOLOv8模型訓練到RK3588設備部署和推理 文章中給出了通過ARM設備上面的NPU進行深度學習的模型推理過程,在此之前,我們在收到一塊全新的rk3588開發板后,需要對其進行系統的燒錄,這里以Ubuntu22.04系統為例。 目錄 1.獲取待燒錄系統的鏡像 2.燒錄工具準備 2.1…

AI評測的科學之道:當Benchmark遇上統計學

AI評測的科學之道&#xff1a;當Benchmark遇上統計學 —— 如何客觀評估大模型能力&#xff0c;避免落入數據陷阱 在人工智能尤其是大語言模型&#xff08;LLU&#xff09;爆發式發展的今天&#xff0c;各類模型榜單&#xff08;如Open LLM Leaderboard、LMSys Arena&#xff0…