Использование gsl :: zstring_view с C API - PullRequest
0 голосов
/ 03 июля 2019

Я пытаюсь использовать современные подходы к обработке строк (например, std::string_view или GSL string_span) для взаимодействия с C API (DBus), который принимает строки как завершается нулем const char* с, например

DBusMessage* dbus_message_new_method_call(
    const char* destination,
    const char* path,
    const char* iface,
    const char* method 
    )

string_view и string_span не гарантируют, что их содержимое заканчивается нулем - так как промежутки являются парами (char* start, ptrdiff_t length), это во многом суть. Но GSL также предоставляет zstring_view, который равен , который гарантированно завершается нулем. комментарии вокруг zstring_span предполагают, что он предназначен именно для работы с устаревшими API-интерфейсами и API-интерфейсами C, но как только я начал его использовать, я столкнулся с несколькими трудностями:

  1. Представление строкового литерала в виде string_span тривиально:

    cstring_span<> bar = "easy peasy";
    

    , но для представления его как zstring_span требуется, чтобы вы обернули литерал в вспомогательную функцию:

    czstring_span<> foo = ensure_z("odd");
    

    Это делает объявления более шумными, и также кажется странным, что литерал (который гарантированно заканчивается нулем) неявно не конвертируется в zstring_span. ensure_z() также не constexpr, в отличие от конструкторов и преобразований для string_span.

  2. Есть похожая странность с std::string, которая неявно преобразуется в string_span, но не zstring_span, даже если std::string::data() гарантированно возвращает нулевую последовательность с C ++ 11 , Опять же, вы должны позвонить ensure_z():

    zstring_span<> to_zspan(std::string& s) { return ensure_z(s); }
    
  3. Кажется, есть некоторые проблемы с правильностью. Выше работает, но

    czstring_span<> to_czspan(const std::string& s) { return ensure_z(s); }
    

    не компилируется, с ошибками из-за невозможности преобразования из span<char, ...> в span<const char, ...>

  4. Это меньшая точка, чем другие, но функция-член, которая возвращает char* (который вы бы передавали в C API, такой как DBus), называется assume_z(). Что значит предполагается , когда конструктор zstring_span ожидает завершенный нулем диапазон ?

Если zstring_span предназначен «для преобразования нулевых оконечных промежутков в унаследованные строки», почему его использование здесь кажется таким громоздким? Я неправильно это использую? Есть что-то, что я пропускаю?

1 Ответ

0 голосов
/ 03 июля 2019

Это «громоздко» отчасти потому, что должно быть.

Это:

zstring_span<> to_zspan(std::string& s) { return ensure_z(s); }

Является не безопасной операцией.Зачем?Поскольку, хотя верно, что s является NUL-символом, вполне возможно, что фактический s содержит внутренние NUL-символы.Это законная вещь, которую вы можете сделать с std::string, но zstring_span и кто бы то ни был, с этим не справится.Они будут обрезать строку.

В отличие от этого, преобразования string_span/view безопасны с этой точки зрения.Потребители таких строк берут строку размера и, следовательно, могут обрабатывать встроенные NUL.

Поскольку преобразование zstring_span небезопасно, должна быть некоторая явная запись о том, что выполняется что-то потенциально небезопасное.ensure_z представляет эту явную запись.

Другая проблема заключается в том, что в C ++ нет механизма, позволяющего определить разницу между строковым аргументом и любым старым параметром const char* или const char[].Поскольку голый const char* может быть или не быть строковым литералом, вы должны предположить, что это не так, и, следовательно, использовать более подробное преобразование.

Кроме того, строковые литералы C ++ могут содержать встроенные NUL-символы, поэтомуПриведенные выше рассуждения применимы.

Проблема const выглядит как ошибка кода, и вам, вероятно, следует подать ее как таковую.

...