狠狠撸

狠狠撸Share a Scribd company logo
C++1zにstring_viewが
導入されてうれしいので
紹介します
H.Hiro (@h_hiro_)
お久しぶりです
H.Hiroです
?名古屋で研究の仕事しています
?C++はかなり使います
(新しいアルゴリズムを考えて試す)
?Boostは最近ちょっとご無沙汰…
?最近、開発したいプログラムのネタが
思い浮かぶも時間が取れず停滞中
今回のテーマ
部分文字列
みんな
使いますよね
std::string foo =
"Boost C++ Library";
std::string bar =
foo.substr(6, 3);
std::cout << bar << std::endl;
// prints "C++"
ただ、これ
C++を使っている人だと
「使いたくない」
ってときもありませんか
ただ、これ
C++を実行効率重視の
ために使っている人だと
「使いたくない」
ってときもありませんか
std::string foo =
"Boost C++ Library";
std::string bar =
foo.substr(6, 3);
ヒープ領域
(newとかで確保されたメモリ領域に利用する)
std::string foo =
"Boost C++ Library";
std::string bar =
foo.substr(6, 3);
ヒープ領域
(newとかで確保されたメモリ領域に利用する)
B o o s t C + + L i b r a r y
std::string foo =
"Boost C++ Library";
std::string bar =
foo.substr(6, 3);
ヒープ領域
(newとかで確保されたメモリ領域に利用する)
B o o s t C + + L i b r a r y
C + +
std::string foo =
"Boost C++ Library";
std::string bar =
foo.substr(6, 3);
std::cout << bar << std::endl;
// prints "C++"
substrする
文字数ぶんの
メモリを
確保する必要
そこで、
考えられる方法
そもそも、文字列って
連続したメモリ領域に
確保されてるんだから
B o o s t C + + L i b r a r y
B o o s t C + + L i b r a r y
std::string foo = "Boost C++ Library";
std::pair<const char*, std::size_t>
bar = std::make_pair( , );
別にこれで
いいじゃないか
長ささえわかればよい始点のポインタと
&foo[6] 3
これが
今回紹介する
string_viewの
大枠です
std::string foo = "Boost C++ Library";
std::pair<const char*, std::size_t>
bar = std::make_pair( , );
string_viewとは
単に「 と
を組にして保持する
クラス」です
&foo[6] 3
始点のポインタ
長さ
ちなみに
実装の説明は
これでほとんど
終わりです
が、もちろん、
これで
終わるわけは
ありません
「実際の使い方」
「どんな場面で使われているのか」
「私が何でこれを時間をかけて紹介
しようと思ったのか」
なども紹介します
使ってみる
string_viewの実装状況
gccの場合:gcc7で対応予定
https://gcc.gnu.org/onlinedocs/libstdc++/manual/status.html
clangの場合:?
Visual Studioの場合:?
標準で入ること
前提でコードを
書くのは
もう少し待つとして
Boost.string_view
を使います
?もともと、Boostでは
「boost::string_ref」という
クラス名でした
?Boost 1.61.0以降
「boost::string_view」が追加され
若干機能が増えています
※C++標準として当初提案されたもの(N3442)
のみならず、より新しいもの(N4480)を
反映させているようです
Boost.勉強会 #21 札幌「C++1zにstring_viewが導入されてうれしいので紹介します」
boost.string_viewにあって
boost.string_refにないもの
traits対応
move対応(?)
noexcept対応
使う
ヘッダファイル
だけで利用できる
Boost
ライブラリなので
Boostのサイトで
ダウンロードして
そのパスを読み込む
ようにすればいいだけ
$ g++ sample.cpp
-I ダウンロードしたパス
コード例
#include <boost/utility/string_view.hpp>
// "utility"必要です!
// さっきのコードを
// boost.string_viewで
// 書き換えてみる
std::string foo =
"Boost C++ Library";
boost::string_view
bar(&foo[6], 3);
std::cout << bar << std::endl;
// 元の文字列が変わると、
// string_view側も変わる
// (あくまで、元の文字列の
// 一部を参照しているだけ)
(前ページに続いて)
foo[7] = 'P';
foo[8] = 'P';
std::cout << bar << std::endl;
// string_viewのコンストラクタ
// 引数1つ
boost::string_view sv1("foo"); // const char*
std::string b("bar");
boost::string_view sv2(b); // std::string
boost::string_view sv3(sv2); // string_view
// 引数2つ
// 「const char* ポインタ, 長さ」。
// 「std::string, 長さ」などはできない。
boost::string_view sv4(sv1.data(), 3);
boost::string_view sv4(b.data(), 3);
// string_viewのAPI
// std::stringと似たものが揃っている
// ※内容を変更するAPIはない
boost::string_view sv1("boost");
std::cout << sv1[2] << std::endl; // 'o'
boost::string_view
sv6 = sv1.substr(1, 3);
std::cout << sv6 << std::endl; // "oos"
std::cout << sv1.find("oo") << std::endl;
// 見つけられる。この場合1になる
APIがstd::stringと
一貫性を持たせて
あるので
std::stringを
使い慣れていれば
そんなに手間は
感じないだろうし
今まで引数をstd::stringに
していたものを、string_viewに
置き換えるのも楽
char foo(const std::string & bar)
{ return bar[0]; }
↓
char foo(boost::string_view bar)
{ return bar[0]; }
※string_viewはstd::stringから暗黙に変換可
「本当はstd::stringじゃないんだけど
std::stringみたいな性質を持ってる
から、似た扱いができるようにしよう」
と設計されてるのがポイントです
(デザインパターンでは
「Proxy(代理)パターン」といいます)
boost::string_viewで利用できるメソッド
<std::stringと共通>
size length max_size empty
begin end (c, r付き含む) front back
at data clear operator[]
compare (各種比較演算子を含む)
find (rfindなども含む) substr
<独自のもの>
remove_prefix remove_suffix
string_viewは
どんな場面で
使われているのか
最初に
言いたかったこと
私も、ほぼ同じ
機能のライブラリが
欲しくて、作った
ことがあった
fundoshi.hpp (2011年初版公開)
https://github.com/maraigue/fundoshi.hpp
fundoshi.hpp (2011年初版公開)
https://github.com/maraigue/fundoshi.hpp
参照:
2012.11.17
CLR/H&札幌C++勉強会 発表資料
http://www.slideshare.net/maraigue/20121117-clrhc-fundoshihpp
このときは、
文字列検索アルゴリズムのために
利用していた
かなり後になって
同じようなことを
している人が
多数いると知った
汎用的なライブラリ
?StringPiece (Google)
ライブラリの一機能として提供
?Qtの "QStringRef"
?Swiftの "CFStringRef"
?JUCEの "StringRef"
内部処理のために?利用
?LLVMの "StringRef"
?gRPCの "string_ref"
だから、
Boostにも入ったし
のちに標準化も
されたといえる
実際、
どんな場面で
使われているのか
利用例:
Qtの "QStringRef" がある箇所
?QRegularExpressionMatch
(正規表現のマッチング結果)
?XMLパーサーの解析結果
QString foo("boost C++ library");
QRegularExpression pat("C..");
QRegularExpressionMatch
mat = pat.match(foo);
mat.capturedRef();
// ↑マッチした部分をQStringRefで返す
Boost.String_Refのドキュメントに
書かれていた、利用が見込まれる
ケース
?HTTPレスポンスから、必要な
部分だけを返す
さっきの「XMLパーサーの解析結果」
と似た用法ですね
利用例:
LLVMの "StringRef" がある箇所
?(おそらく)
メソッド名等を保持する部分
(完全に読めているわけではなくて、
コード中にStringRefが見つかった場所
近辺を読んだだけですが、そんな雰囲気
だった)
string_refを標準化しようという
提案文書(N3442)にて
利用を想定していたケース
(1/3)
引数の型はstd::stringであるが、
「std::string以外の値を引数として
渡す場合」は呼び出す側でコピーを
取っておく必要がある場合
string_refを標準化しようという
提案文書(N3442)にて
利用を想定していたケース
(2/3)
char*ポインタと文字列長を
組にした引数を受け取っているような
箇所の置き換え
?パフォーマンスを理由にそうする
ことを想定?
?内部的にC言語のAPIを呼ぶ場合
とか?
string_refを標準化しようという
提案文書(N3442)にて
利用を想定していたケース
(3/3)
?連続したメモリ上に確保されている
ものであれば何でも扱える、という
型が必要な場合
std::stringもstd::vector<char>も
統一的に扱いたいとか?
部分文字列を
取る操作が
あるならば、
これが使えないか
考えてみよう
といえるくらい
汎用的な
ライブラリです
おわりに
部分文字列を
取るときに
付きまとう問題
「余計なメモリ確保」
B o o s t C + + L i b r a r y
C + +
それをスマートに
解決してくれる
string_view
祝?
標準化が有力に!
参考資料
C++標準化提案
? N3442(string_refの提案)
http://www.open-std.org/jtc1/sc22/wg21/docs/
papers/2012/n3442.html
? N4606(C++1zのドラフト)
http://www.open-std.org/JTC1/SC22/WG21/docs/
papers/2016/n4606.pdf
実装(本資料中で示したもの関連)
? Boost http://www.boost.org/
? Qt https://www.qt.io/
? LLVM http://www.llvm.org/
ありがとう
ございました

More Related Content

Boost.勉強会 #21 札幌「C++1zにstring_viewが導入されてうれしいので紹介します」