文字列の基本構造と種類
C++では、テキストデータを扱うために主に二種類の文字列表現が用いられる:
- 文字配列(Cスタイル):
char型の配列で表され、終端にヌル文字\0を持つ。宣言例:char message[] = "Hello";。 - std::stringクラス:標準ライブラリが提供する高機能な文字列型。動的メモリ管理を内包し、多くの操作が簡潔に記述可能。例:
std::string greeting = "Hello";。
両者の特徴比較
| 項目 | Cスタイル文字列 | std::string |
|---|---|---|
| メモリ制御 | 手動で確保・解放が必要。バッファオーバーランのリスクあり | 自動的に管理されるため安全。再割り当ても内部で処理 |
| 安全性 | 終端文字の扱いや領域計算ミスによりクラッシュの原因に | 範囲チェックや自動終端処理により堅牢性が高い |
| 利用可能な操作 | strlen, strcpy, strcmp などのC関数群に依存 |
insert(), erase(), substr() など豊富なメンバ関数を提供 |
| 互換性 | 低レベルAPIやC言語との連携に適している | STLアルゴリズムやストリーム入出力との親和性が高い |
| パフォーマンス | 余計なオーバーヘッドがなく、高速な場合が多い | 動的拡張時に一時的なコストが発生することもある |
実際のコードでの違い
// Cスタイル:結合には注意が必要
char a[32] = "Start";
strcat(a, "End"); // aのサイズが十分か確認必須
// std::string:直感的かつ安全
std::string part1 = "Start";
std::string part2 = "End";
part1 += part2; // 自動で容量調整され、安全に連結
主要な操作手法
連結処理
演算子+またはappend()を使用できるが、数値を直接連結することはできない。変換が必要:
std::string result = "Value: ";
result += std::to_string(123); // 正しい方法
入力操作
std::cin >> strは空白で切断されるため、行全体を読み込むにはstd::getline()を使うべき:
std::string line;
std::getline(std::cin, line); // スペース含む一文を取得
検索と置換
部分文字列の位置検出にはfind()、存在すれば置換を実行:
std::string text = "Replace this old part";
size_t index = text.find("old");
if (index != std::string::npos) {
text.replace(index, 3, "new"); // "old" → "new"
}
パフォーマンス改善のための戦略
予約領域の設定
頻繁に追加がある場合は、あらかじめメモリを確保することで再割り当ての回数を削減:
std::string buffer;
buffer.reserve(512); // 最大512文字を見越して確保
コピー回避技術
不要なコピーを避けるために、所有権の移動(ムーブセマンティクス)を活用:
std::string createString() {
return "temporary data";
}
std::string target = std::move(createString()); // コピーなしで転送
また、多数の小規模な連結を行う場合は、std::ostringstreamの使用が推奨される:
#include <sstream>
std::ostringstream oss;
oss << "ID: " << 42 << " Name: " << "Alice";
std::string final = oss.str();
適用シーンと選定基準
- Cスタイル文字列:リアルタイム性が求められる組み込みシステム、外部バイナリインターフェースとの接続時。
- std::string:アプリケーションロジック、ユーザー入出力、複雑な文字列処理を伴う一般開発。
C++11以降では、std::stringに対する統一初期化構文やムーブ対応の強化により、使い勝手と効率が共に向上しており、新規プロジェクトでは標準的に採用される傾向にある。