【C++17】std::string_view の使い方 | 文字列コピーを回避しパフォーマンス向上

目次

はじめに

C++で、関数に文字列を渡す際、引数を const std::string& とするのが一般的でした。しかし、この方法にはパフォーマンス上の問題があります。もし、関数にC言語スタイルの文字列リテラル(例: "Hello") を渡そうとすると、その場で一時的な std::string オブジェクトが生成され、メモリ確保とコピーが発生してしまうのです。

この問題を解決するのが、C++17で導入された std::string_view です。string_view は、既存の文字列データの「一部分」または「全部」を指し示すだけの、所有権を持たない軽量なオブジェクトです。

この記事では、string_view がどのようにして不要な文字列コピーを防ぎ、コードのパフォーマンスを向上させるのかを解説します。


【前提】C++17とは?

C++17は、2017年に正式化されたC++言語の規格です。std::string_view はこのC++17で導入されたため、利用するにはC++17に対応したコンパイラが必要です。


string_view を使ったサンプルコード

このコードは、文字列の一部を切り出して表示する関数を、従来の const string& を使った場合と、string_view を使った場合の2通りで定義し、その使われ方の違いを示します。

完成コード

#include <iostream>
#include <string>
#include <string_view> // string_view を使うために必要

using namespace std;

// 従来の const string& を使う関数
void printSubstring_String(const string& s) {
    cout << s.substr(0, 5) << endl;
}

// C++17の string_view を使う関数
void printSubstring_StringView(string_view sv) {
    cout << sv.substr(0, 5) << endl;
}

int main() {
    string my_string = "Hello, Modern C++";
    const char* c_style_string = "This is a C-style string";

    cout << "--- const string& を使った場合 ---" << endl;
    // string を渡す -> コピーは発生しない
    printSubstring_String(my_string);
    // C言語スタイル文字列を渡す -> 一時的なstringオブジェクトが生成され、コピーが発生
    printSubstring_String(c_style_string);

    cout << "\n--- string_view を使った場合 ---" << endl;
    // string を渡す -> コピーは発生しない
    printSubstring_StringView(my_string);
    // C言語スタイル文字列を渡す -> コピーは発生しない
    printSubstring_StringView(c_style_string);
    // string_view を渡す -> もちろんコピーは発生しない
    printSubstring_StringView(string_view{"This is a string_view literal"});
    
    return 0;
}

コードの解説

void printSubstring_String(const string& s)

この従来の関数に、C言語スタイルの文字列 c_style_string を渡すと、const string& 型の引数に合わせるために、一時的な std::string オブジェクトがその場で生成されます。この時、文字列 "This is a C-style string" を格納するためのメモリ確保と、文字のコピーが発生します。

void printSubstring_StringView(string_view sv)

この新しい関数は、引数として string_view を受け取ります。string_view は、std::string からも、C言語スタイルの文字列リテラルからも、コピーなしで構築できます。

  • printSubstring_StringView(my_string): string_viewmy_string の内部バッファを直接指し示します。
  • printSubstring_StringView(c_style_string): string_viewc_style_string のメモリアドレスを直接指し示します。

いずれの場合も、新たなメモリ確保や文字列のコピーは一切発生しませんstring_view は、ポインタと長さ情報を持つだけの非常に軽量なオブジェクトです。

string_view の注意点

string_view は、あくまで既存の文字列への「眺め」であり、データの所有権を持ちません。そのため、string_view が指し示している元の文字列が、string_view よりも先に破棄されてしまうと、「ダングリング(ぶら下がり)」状態になり、アクセスすると未定義の動作を引き起こします。


まとめ

今回は、C++17の std::string_view を使って、不要な文字列コピーを回避し、パフォーマンスを向上させる方法を解説しました。

  • std::string_view は、文字列の所有権を持たない、読み取り専用のビュー。
  • 関数の引数を const std::string& から std::string_view に変更することで、様々な種類の文字列をコピーコストなしで受け取れるようになる。
  • 指し示している元の文字列の寿命には、常に注意を払う必要がある。

結論として、関数の引数で、文字列の所有権が必要なく、単に読み取るだけでよい場合は、常に const std::string& よりも std::string_view を使うのが、現代C++のベストプラクティスです。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

私が勉強したこと、実践したこと、してることを書いているブログです。
主に資産運用について書いていたのですが、
最近はプログラミングに興味があるので、今はそればっかりです。

目次