yohhoyの日記

技術的メモをしていきたい日記

文字列リテラルからのstd::string_view構築

C++1z(C++17)において文字列リテラルから文字列ビューstd::string_viewへ変換する場合、暗黙の型変換ではなくユーザ定義リテラル""svの明示利用が望ましい。

  • string_viewクラスはC文字列(const char*)からの非explicit変換コンストラクタを提供する。
  • string_viewユーザ定義リテラルstd::literals::string_view_literals名前空間で定義される。*1
  • 計算量(complexity):暗黙コンストラクタでは文字列リテラル長に比例 O(N) するが、ユーザ定義リテラル""svでは定数時間 O(1) が保証される。
    • 現実問題として計算量が問題になるほど長い文字列リテラルを扱うケースは稀だろう。また同コンストラクタはconstexpr指定されているため、コンパイル時最適化によって同一アセンブリが出力されると期待できる。*2
  • NUL文字の扱い:文字列リテラルがNUL文字('\0')を含む場合、暗黙コンストラクタではNUL文字以降が切り捨てられてしまう。ユーザ定義リテラル""svではNUL文字以降も正しく扱うことができる。
    • “NUL文字を含む文字列リテラル” を扱うケースがどれ程あるかは疑問符だが、ユーザ定義リテラルを用いるデメリットは存在しないハズ。
// C++1z(C++17)
#include <string_view>
using namespace std::literals::string_view_literals;

// 通常のヌル終端文字列
std::string_view sv1 = "ABC";   // OK: "ABC" size=3
std::string_view sv2 = "ABC"sv; // OK: "ABC" size=3

// NUL文字'\0'を含む文字列
std::string_view sv3 = "X\0Y\0Z";   // NG: "X" size=1
std::string_view sv4 = "X\0Y\0Z"sv; // OK: "X\0Y\0Z" size=5

N4659(C++17 DIS) 24.4/p3, 24.4.2.1/p3-7, 24.4.6/p1より引用。

3 The complexity of basic_string_view member functions is O(1) unless otherwise specified.

constexpr basic_string_view(const charT* str);
3 Requires: [str, str + traits::length(str)) is a valid range.
4 Effects: Constructs a basic_string_view, with the postconditions in Table 64.
5 Complexity: O(traits::length(str)).

constexpr basic_string_view(const charT* str, size_type len);
6 Requires: [str, str + len) is a valid range.
7 Effects: Constructs a basic_string_view, with the postconditions in Table 65.

constexpr string_view operator""sv(const char* str, size_t len) noexcept;
1 Returns: string_view{str, len}.

関連URL

*1:literals および string_view_literals はインライン名前空間となっているため、using namespace宣言では std::literals::string_view_literals または std::literals または std::string_view_literals いずれも利用可能。

*2:GCC 7.1/-std=c++1z -O1オプション指定では実際に同じアセンブリ出力が得られる。https://gist.github.com/yohhoy/52b9de2a9f9b3f05b263b5d979013356