C++において、文字列の長さを取得するという操作は、あらゆるプログラムの基本となる処理の一つです。

ユーザーインターフェースでの入力制限や、テキストデータのパース、バッファサイズの計算など、文字列のサイズを正しく把握することは、バグのない堅牢なコードを書くための第一歩と言えます。

しかし、C++のstd::stringには、長さを取得するためのメソッドが複数存在し、さらに日本語のようなマルチバイト文字を扱う際には、単純なメソッド呼び出しだけでは期待した結果が得られないケースもあります。

本記事では、最新のC++標準を念頭に置きながら、文字列長取得の基本から応用までを詳しく解説します。

std::string::size()とstd::string::length()の基本

C++の標準ライブラリであるstd::string(正確にはstd::basic_string<char>の別名)には、文字列の長さを取得するためのメンバ関数として、size()length()の二つが用意されています。

まずはこれらの基本的な使い方と違いについて確認しましょう。

二つのメソッドに違いはあるのか

結論から述べると、size()とlength()の間に動作上の違いは全くありません。どちらも文字列が保持している要素の数(バイト数)を返し、計算量もO(1)、つまり定数時間で実行されます。

これは、std::stringの内部構造が、自身のサイズ情報をメンバ変数として保持しているため、呼び出しのたびに文字を数え直す必要がないからです。

C++
#include <iostream>
#include <string>

int main() {
    std::string text = "Hello, C++";

    // size() を使用
    std::cout << "size(): " << text.size() << std::endl;

    // length() を使用
    std::cout << "length(): " << text.length() << std::endl;

    return 0;
}
実行結果
size(): 10
length(): 10

上記のコードが示す通り、同じ値が返されます。

どちらを使用するかは、プロジェクトのコーディング規約や個人の好みに委ねられています。

なぜ二つの名前が存在するのか

なぜ同じ機能を持つ関数が二つ存在するのでしょうか。

それはC++の歴史と、他の標準ライブラリとの一貫性に理由があります。

size()は、STL(Standard Template Library)のコンテナとしてのインターフェースに従うために存在します。

std::vectorstd::listなど、他のコンテナと共通の作法で要素数を取得できるように設計されています。

一方で、length()は、伝統的なプログラミングの文脈において「文字列の長さ」を表現する際により直感的であるという理由で用意されました。

モダンなC++開発においては、他のコンテナとの一貫性を重視してsize()が好まれる傾向にありますが、文字列であることを強調したい場合にlength()を用いることも一般的です。

文字列の長さを取得する際の注意点

単純にメソッドを呼び出すだけで長さを取得できるstd::stringですが、実務においてはいくつか注意すべき点があります。

特に「文字数」と「バイト数」の混同は、深刻なバグを引き起こす原因となります。

バイト数と文字数の混同

std::string::size()が返すのは、あくまで「文字数」ではなく「バイト数」であるという点は、最も重要な制約事項です。

C++の標準的なchar型は1バイト(8ビット)として定義されています。

ASCII文字(半角英数など)のみを扱う場合は「1文字 = 1バイト」となるため問題になりませんが、日本語などの全角文字を扱う場合には事情が異なります。

現在の主流であるUTF-8エンコーディングでは、日本語1文字は通常3バイトから4バイトで表現されるため、size()を呼び出すと、見た目の文字数よりも大きな値が返されます。

空の文字列を確認する方法

文字列の長さが0であるかどうかを確認したい場合、text.size() == 0と比較するよりも、empty()メンバ関数を使用することが推奨されます。

C++
std::string text = "";

if (text.empty()) {
    // 文字列が空の場合の処理
}

empty()を使用する方が、コードの意図が明確になり、可読性が向上します。

また、ごく一部の特殊なコンテナ実装においては、size()よりもempty()の方が効率的な場合があるため、パフォーマンス面でも有利に働く可能性があります。

マルチバイト文字列(日本語)の長さを正しく扱う方法

日本語環境において「文字列の長さ」を取得したい場合、多くのケースでは「見た目上の文字数(コードポイント数)」を指しているはずです。

これを実現するためには、単なるsize()以外の方法を検討する必要があります。

std::stringが保持するのは「バイト数」

以下の例を見てください。

UTF-8で保存されたソースコード上で日本語の長さを測定します。

C++
#include <iostream>
#include <string>

int main() {
    std::string s = "こんにちは";
    std::cout << "バイト数: " << s.size() << std::endl;
    return 0;
}
実行結果
バイト数: 15

「こんにちは」は5文字ですが、結果は15となります。

これは、UTF-8において「こ」「ん」「に」「ち」「は」がそれぞれ3バイトずつ消費しているためです。

マルチバイト文字を扱う場合は、size()の結果を文字数として扱ってはいけません

UTF-8文字列の文字数をカウントする手法

UTF-8の文字列から正確な文字数(コードポイント数)をカウントするには、各文字の先頭バイトを判定して、後続のバイトを読み飛ばす処理が必要です。

手動で実装することも可能ですが、C++20以降ではより洗練された方法が登場しています。

従来のC++で広く使われてきた方法は、std::mbstowcsなどを使用してワイド文字列に変換してから数える方法や、各文字のビットパターンをチェックする方法です。

C++
#include <iostream>
#include <string>

// 簡易的なUTF-8文字数カウント関数
size_t count_utf8_characters(const std::string& str) {
    size_t count = 0;
    for (size_t i = 0; i < str.size(); ++i) {
        unsigned char c = static_cast<unsigned char>(str[i]);
        // UTF-8のマルチバイト文字の先頭バイトまたはASCIIバイトをカウント
        // 10xxxxxx という形式のバイトは後続バイトなのでカウントしない
        if ((c & 0xC0) != 0x80) {
            count++;
        }
    }
    return count;
}

int main() {
    std::string s = "こんにちはC++";
    std::cout << "バイト数: " << s.size() << std::endl;
    std::cout << "文字数: " << count_utf8_characters(s) << std::endl;
    return 0;
}
実行結果
バイト数: 18
文字数: 8

このコードでは、UTF-8の仕様に基づき、各バイトのビットをチェックして「文字の開始位置」のみをカウントしています。

これにより、日本語とアルファベットが混在していても正しく文字数を取得できます。

std::u8stringとstd::u32stringの活用

C++20からは、UTF-8エンコードされた文字列を明示的に扱うための型として、std::u8stringが導入されました。

これにより、型システム上で文字列のエンコーディングを区別できるようになりました。

また、文字数を最も簡単に数える方法の一つとして、std::u32string(UTF-32文字列)への変換があります。

UTF-32は1文字を固定4バイトで表現するため、そのsize()はそのままコードポイント数に一致します。

モダンC++における文字列長操作(C++20/23/26)

C++の進化に伴い、文字列の扱いもより安全で効率的なものへと変わってきています。

2026年現在の開発環境においては、以下のような機能の活用が一般的になっています。

std::string_viewによる効率的な長さ取得

C++17で導入され、C++20/23でさらに強化されたstd::string_viewは、文字列の所有権を持たずに参照だけを行うクラスです。

関数の引数などで文字列を受け取る際、const std::string&の代わりにstd::string_viewを使用することで、不必要なメモリコピーを回避できます。

std::string_viewsize()メソッドを持っており、これは参照先の部分文字列の長さを瞬時に返します。

C++
#include <iostream>
#include <string_view>

void print_length(std::string_view sv) {
    std::cout << "表示中の文字列長: " << sv.size() << std::endl;
}

int main() {
    print_length("Hello World"); // リテラルを渡してもコピーが発生しない
    return 0;
}

最新の文字コード標準への対応状況

C++23以降、テキスト処理に関する標準ライブラリの整備が進んでいます。

std::format(C++20以降)の普及により、文字列の整形と長さの計算を同時に行う処理が非常にスマートに記述できるようになりました。

さらに、C++26に向けた議論の中では、より高度なUnicode操作を標準ライブラリでサポートする動きもあります。

現時点では、Unicodeの正規化(Normalization)や書記素クラスター(Grapheme Cluster)のカウント(例:家族の絵文字や濁点付き文字を1文字と数える処理)を標準ライブラリだけで完璧に行うのは難しいため、高度な処理が必要な場合はICU (International Components for Unicode)などの外部ライブラリとの併用も検討されます。

パフォーマンスとベストプラクティス

文字列の長さを取得する際のパフォーマンスについても触れておきます。

  1. size()とlength()を優先する
    前述の通り、これらはO(1)です。ループの中で頻繁に呼び出してもパフォーマンス上の問題はほとんどありません。
  2. C言語スタイルのstrlen()は避ける
    C言語のstrlen(s.c_str())を呼び出すと、文字列の終端ヌル文字を探すためにO(N)の計算時間がかかります。特別な理由がない限り、std::stringのメンバ関数を使用してください。
  3. マルチバイト文字のカウントは計算コストを意識する
    UTF-8の文字数を数える処理は、文字列の全要素を走査するためO(N)のコストがかかります。長大なテキストに対して頻繁に実行する必要がある場合は、結果をキャッシュするなどの工夫が必要です。
  4. string_viewの活用
    部分文字列(サブストリング)の長さを頻繁に扱う場合、substr()で新しい文字列オブジェクトを生成するのではなく、string_viewで範囲を切り出すことで、メモリ割り当てのオーバーヘッドをゼロにできます。
機能計算量主な用途
size() / length()O(1)バイト数、バッファ管理
empty()O(1)空チェック(推奨)
UTF-8文字数カウントO(N)ユーザー表示、文字数制限
strlen()O(N)C APIとの連携(非推奨)

まとめ

C++における文字列の長さ取得は、一見単純に見えて奥が深いテーマです。

基本的には、ASCII文字のみを扱うのであれば size() または length() を使用することで、高速かつ正確に長さを取得できます。

しかし、日本語をはじめとするマルチバイト文字が介在する場合、それらが返す値は「バイト数」であるという事実を常に意識しなければなりません。

2026年現在のモダンなC++開発においては、std::u8stringstd::string_viewを適切に使い分け、必要に応じてUnicodeのコードポイントを考慮したカウント処理を実装することが求められます。

この記事で紹介した手法を組み合わせることで、文字コードのトラブルに強い、堅牢な文字列処理を実装することができるでしょう。

文字列操作はプログラムの品質を左右する重要な要素です。

適切なメソッドを選択し、メモリ効率と正確性を両立させたコードを目指しましょう。