Daily bit(e) C++. Работа с массивами в стиле C, используя std::span

Добавлено 30 июля 2026 в 02:06

Daily bit(e) C++ 53, безопасное обертывание массивов в стиле C с помощью std::span из C++20.

Daily bit(e) C++

Передача данных в виде массивов в стиле C может быть неизбежной при взаимодействии с устаревшим кодом или API на C. Это может привести к ошибкам при отслеживании размера массива.

В C++20 был представлен std::span, представление, которое может обернуть непрерывный блок памяти в интерфейс диапазона. Это позволяет нам безопасно использовать алгоритмы и представления для обработки данных без копирования их в контейнер C++.

std::span также может быть преобразован в std::span или std::byte, предоставляя доступ к представлению базового объекта.

#include <cstdint>
#include <span>
#include <vector>
#include <ranges>

#include <utility>
#include <print>

size_t read(char* buffer, size_t size);
int get_data(char** buffer, size_t* size);

int main() 
{
    char buffer[16];
    auto view = std::span(buffer);
    // Вызов C API, используя обернутый буфер
    size_t cnt = read(view.data(), view.size());
    // Обработка суб-представления на основе количества фактически прочитанных байтов
    for (auto v : view.subspan(0, cnt)) 
        std::print("{} ", v);
    // напечатает: a b c d 


    char* buff;
    size_t length;
    int ret = get_data(&buff, &length);
    if (ret != 0) 
        return ret; 
    // Обернуть C буфер в a std::span
    auto buffer_view = std::span(buff, length);

    // std::span работает как любой другой диапазон,
    // например, обратная итерация:
    for (auto it = buffer_view.rbegin(); it != buffer_view.rend(); ++it) 
    {
    }
    // или комбинирование с представлениями:
    for (auto v : buffer_view | std::views::drop(8)) 
        std::print("{} ", v);
    // напечатает: i j k l m n o p


    struct Data {
        int x;
        int y;
    };

    std::vector<Data> data{{2,3},{1,5},{4,4}};
    // Доступ к базовому представлению:
    std::span<std::byte> bytes = std::as_writable_bytes(std::span(data));

    std::print("0x");
    for (auto v : bytes)
        std::print("{:x}", std::to_underlying(v));
    // напечатает: 0x200030001000500040004000
    std::println("");
}

size_t read(char* buffer, size_t size) 
{
    size_t cnt = size >= 4 ? 4 : size;
    for (size_t i = 0; i < cnt; ++i)
        buffer[i] = 'a'+i;
    return cnt;
}

int get_data(char** buffer, size_t* size) 
{
    static char buff_[16]{'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p'};
    *buffer = buff_;
    *size = 16;
    return 0;
}

Пример на Compiler Explorer

Теги

C++ / CppDaily bit(e) C++Массивы в CПрограммирование