【C++】std::basic_string::end をマスターしよう! 文字列操作を極めるための詳細解説
範囲指定に使用
std::basic_string::end
は、std::basic_string::begin
と組み合わせて、文字列全体をイテレートする範囲を指定するために使用されます。例えば、以下のコードは、文字列内のすべての文字をループで処理します。
#include <iostream>
#include <string>
int main() {
std::string str = "Hello, World!";
for (std::string::iterator it = str.begin(); it != str.end(); ++it) {
std::cout << *it;
}
std::cout << std::endl;
return 0;
}
このコードは "Hello, World!" を出力します。
空文字列の場合
空文字列の場合、std::basic_string::end
は std::basic_string::begin
と同じイテレータを返します。つまり、空の範囲を指します。
注意事項
std::basic_string::end
は、const 修飾されたバージョンとそうでないバージョンがあります。const バージョンは、読み取り専用であり、文字列を変更することはできません。std::basic_string::end
で返されるイテレータは、決して逆参照しないでください。これは、未定義の動作を引き起こす可能性があります。
例
以下のコードは、std::basic_string::end
を使って、文字列の最後の文字を取得する方法を示しています。
#include <iostream>
#include <string>
int main() {
std::string str = "Hello, World!";
std::string::iterator it = str.end();
--it;
std::cout << *it << std::endl;
return 0;
}
文字列の範囲を反復処理する
#include <iostream>
#include <string>
int main() {
std::string str = "Hello, World!";
// 文字列の範囲を反復処理し、各文字を出力
for (std::string::iterator it = str.begin(); it != str.end(); ++it) {
std::cout << *it;
}
std::cout << std::endl;
return 0;
}
このコードは以下の出力を生成します。
Hello, World!
最後の文字を取得する
#include <iostream>
#include <string>
int main() {
std::string str = "Hello, World!";
// 最後の文字を取得
std::string::iterator it = str.end();
--it;
std::cout << *it << std::endl;
return 0;
}
d
部分文字列を反復処理する
#include <iostream>
#include <string>
int main() {
std::string str = "Hello, World!";
// 部分文字列 "World" を反復処理し、各文字を出力
std::string::iterator begin = str.begin() + 7; // "World" の先頭位置
std::string::iterator end = str.end();
for (std::string::iterator it = begin; it != end; ++it) {
std::cout << *it;
}
std::cout << std::endl;
return 0;
}
World
#include <iostream>
#include <string>
int main() {
std::string str = "Hello, World!";
std::string subStr = "World";
// サブ文字列 "World" が str に存在するかどうかを確認
std::string::iterator begin = str.begin();
std::string::iterator end = str.end();
std::string::iterator found = std::search(begin, end, subStr.begin(), subStr.end());
if (found != end) {
std::cout << "サブ文字列が見つかりました: " << *found << std::endl;
} else {
std::cout << "サブ文字列は見つかりませんでした" << std::endl;
}
return 0;
}
サブ文字列が見つかりました: W
std::string::size() を使用する
- 欠点: 文字列の終端位置を取得するだけでなく、文字列の長さを取得するため、不要な計算が発生する可能性がある
- 利点: シンプルで分かりやすい
std::string str = "Hello, World!";
std::string::size_type pos = str.size(); // 文字列の長さを取得
std::string::iterator it = str.begin() + pos; // 終端位置のイテレータを取得
std::string::c_str() を使用する
- 欠点: C 言語との互換性が必要な場合にのみ使用すべきであり、パフォーマンス面で不利になる可能性がある
- 利点: C 言語スタイルの文字列終端記号 (
\0
) を利用できる
const char* c_str = str.c_str();
while (*c_str != '\0') {
++c_str;
}
std::string::iterator it = str.begin() + (c_str - str.c_str()); // 終端位置のイテレータを取得
手動でインクリメントする
- 欠点: 煩雑でエラーが発生しやすい
- 利点: 最も軽量な方法
std::string str = "Hello, World!";
std::string::iterator it = str.begin();
for (; it != str.end(); ++it) {
// ...
}
範囲ベース for ループを使用する (C++11 以降)
- 欠点: C++11 以降のコンパイラが必要
- 利点: 簡潔で読みやすい
#include <iostream>
#include <string>
int main() {
std::string str = "Hello, World!";
for (char c : str) {
std::cout << c;
}
std::cout << std::endl;
return 0;
}
std::ranges::begin() と std::ranges::end() を使用する (C++20 以降)
- 欠点: C++20 以降のコンパイラが必要
- 利点: モダンな C++ の書き方
#include <iostream>
#include <string>
#include <ranges>
int main() {
std::string str = "Hello, World!";
for (auto it = std::ranges::begin(str); it != std::ranges::end(str); ++it) {
std::cout << *it;
}
std::cout << std::endl;
return 0;
}
- 簡潔で読みやすいコードが必要な場合は、範囲ベース for ループ (C++11 以降) または
std::ranges::begin()
とstd::ranges::end()
(C++20 以降) を使用するのが良いでしょう。 - パフォーマンスが重要な場合は、手動でインクリメントする方法が最速ですが、煩雑でエラーが発生しやすいことに注意が必要です。
- C 言語との互換性が必要な場合は、
std::string::c_str()
を使用する必要があります。 - シンプルで分かりやすい方法が必要な場合は、
std::string::size()
を使用するのが良いでしょう。